Performance of reading a registry key?
using (RegistryKey registryKey = Registry.CurrentUser.OpenSubKey(@"Software/Copium"))
{
return (string)registryKey.GetValue("BinDir");
}
The registry is a convenient place to record persistent cross-process data in a uniform and multi-thread-safe manner. It roams with the user if you store it in HKEY_CURRENT_USER, and individual keys can be secured (even on systems that use FAT, which doesn't otherwise support security).
But that doesn't mean that it's free.
The cost of opening a key, reading a value, and closing it is around 60,000 to 100,000 cycles (I'm told). And that's assuming the key you're looking for is in the cache. If you open the key and hold it open, then the act of reading a value costs around 15,000 to 20,000 cycles. (These numbers are estimates for Windows XP; actual mileage may vary.)
Consequently, you shouldn't be reading a registry key in your inner loop. Not only does it cost you CPU time at query time, but the constant hammering of the registry means that the data structures used by the registry to locate and store your key (including the entry in the registry cache) are kept in the system working set. Don't read a registry key on every mouse move; read the value once and cache the result. If you need to worry about somebody changing the value while your program is running, you can establish a protocol for people to follow when they want to change a setting. Windows, for example, uses functions such as SystemParametersInfo to manipulate settings that are normally cached rather than read from the registry each time they are needed. Calling the update function both updates the registry and the in-memory cache. If you can't establish a mechanism for coordinating changes to the setting, you can set a change notification via the RegNotifyChangeKeyValue function so that you are notified when the value changes.
Whenever possible, optimize for the common case, not the rare case. The common case is that the registry value hasn't changed. By using a notification mechanism, you move the cost of "But what if the value changed?" out of your inner loop and into code that doesn't execute most of the time. (Remember, the fastest code is code that never runs.)
Of course, you don't want to burn a thread waiting on the notification event. I use the thread pool. The RegisterWaitForSingleObject function lets you tell the thread pool, "Hey, could you call me when this object is signalled? Thanks." The thread pool then does the work of combining this with all the other handles it has been asked to wait for into a giant WaitForMultipleObjects call. That way, one thread can handle multiple waits.
One caveat to heed with the RegNotifyChangeKeyValue function is that the notification has thread affinity! If the thread that calls the RegNotifyChangeKeyValue function exits, the notification is raised. This means that you shouldn't call the function from a thread pool thread, since the system will destroy threads in the thread pool when the work list goes idle and their presence is no longer needed. If you mess up and call it from a thread pool thread, you'll find that the event keeps firing spuriously as the thread pool cleanup code runs, making the cure as bad as the disease! Instead, you should create the wait from a persistent thread (say, the thread that actually cares about the value!) and register the wait there. When the event fires on the thread pool, handle the change, then ask your persistent thread to start a new cycle of RegNotifyChangeKeyValue. That way, the event is always associated with your persistent thread instead of with a transient thread pool thread.
But that doesn't mean that it's free.
The cost of opening a key, reading a value, and closing it is around 60,000 to 100,000 cycles (I'm told). And that's assuming the key you're looking for is in the cache. If you open the key and hold it open, then the act of reading a value costs around 15,000 to 20,000 cycles. (These numbers are estimates for Windows XP; actual mileage may vary.)
Consequently, you shouldn't be reading a registry key in your inner loop. Not only does it cost you CPU time at query time, but the constant hammering of the registry means that the data structures used by the registry to locate and store your key (including the entry in the registry cache) are kept in the system working set. Don't read a registry key on every mouse move; read the value once and cache the result. If you need to worry about somebody changing the value while your program is running, you can establish a protocol for people to follow when they want to change a setting. Windows, for example, uses functions such as SystemParametersInfo to manipulate settings that are normally cached rather than read from the registry each time they are needed. Calling the update function both updates the registry and the in-memory cache. If you can't establish a mechanism for coordinating changes to the setting, you can set a change notification via the RegNotifyChangeKeyValue function so that you are notified when the value changes.
Whenever possible, optimize for the common case, not the rare case. The common case is that the registry value hasn't changed. By using a notification mechanism, you move the cost of "But what if the value changed?" out of your inner loop and into code that doesn't execute most of the time. (Remember, the fastest code is code that never runs.)
Of course, you don't want to burn a thread waiting on the notification event. I use the thread pool. The RegisterWaitForSingleObject function lets you tell the thread pool, "Hey, could you call me when this object is signalled? Thanks." The thread pool then does the work of combining this with all the other handles it has been asked to wait for into a giant WaitForMultipleObjects call. That way, one thread can handle multiple waits.
One caveat to heed with the RegNotifyChangeKeyValue function is that the notification has thread affinity! If the thread that calls the RegNotifyChangeKeyValue function exits, the notification is raised. This means that you shouldn't call the function from a thread pool thread, since the system will destroy threads in the thread pool when the work list goes idle and their presence is no longer needed. If you mess up and call it from a thread pool thread, you'll find that the event keeps firing spuriously as the thread pool cleanup code runs, making the cure as bad as the disease! Instead, you should create the wait from a persistent thread (say, the thread that actually cares about the value!) and register the wait there. When the event fires on the thread pool, handle the change, then ask your persistent thread to start a new cycle of RegNotifyChangeKeyValue. That way, the event is always associated with your persistent thread instead of with a transient thread pool thread.
Create/Edit Windows Registry Keys for TCP/IP Performance Tuning
This topic describes how to tune Windows 2000, Windows XP, and Windows 2003 operating systems for TCP/IP performance. To add a key to the registry, you can either edit it directly as described below or create and execute a .reg file. When you have finished adding or editing these registry keys, you will need to restart the Server. Configure the following settings or variables below according to your specific tuning needs. If necessary, refer to the GlobalSCAPE Knowledge Base article Q10411 - HOWTO: Windows Registry Settings, for the procedure for creating/editing keys and creating a .reg file.TcpTimedWaitDelay
This key determines the time that must elapse before TCP/IP can release a closed connection and reuse its resources. This interval between closure and release is known as the TIME_WAIT state or twice the maximum segment lifetime (2MSL) state. During this time, reopening the connection to the client and server costs less than establishing a new connection. By reducing the value of this entry, TCP/IP can release closed connections faster and provide more resources for new connections. Adjust this parameter if the running application requires rapid release, the creation of new connections, or an adjustment because of a low throughput caused by multiple connections in the TIME_WAIT state.To activate this feature, create the following key:
- Subkey:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\TCPIP\Parameters
- Value name:
TcpTimedWaitDelay
- Value data:
0x0000001e
(Hex 0x0000001e = decimal 30. This value sets the wait time to 30 seconds.)
MaxUserPort
This key determines the highest port number that TCP/IP can assign when an application requests an available user port from the system.To activate this feature, create the following key:
- Subkey:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\TCPIP\Parameters
- Value name:
MaxUserPort
- Value data:
- (minimum)
32768
MaxConnect Backlog
These keys, if many connection attempts are received simultaneously, increase the default number of pending connections that are supported by the operating system.To activate this feature, create the following 4 keys:
- Subkey:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\AFD\Parameters
- Value name:
EnableDynamicBacklog
- Value data:
00000001
- Value name:
MinimumDynamicBacklog
- Value data:
00000020
- Value name:
MaximumDynamicBacklog
- Value data:
00001000
- Value name:
DynamicBacklogGrowthDelta
- Value data:
00000010
KeepAliveInterval
This key determines how often TCP repeats keep-alive transmissions when no response is received.To activate this feature, create the following key:
- Subkey:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\AFD\Parameters
- Value name:
KeepAliveInterval
- Value data:
1
(second)
TcpMaxDataRetranmission
This key determines how many times TCP retransmits an unacknowledged data segment on an existing connection.To activate this feature, create the following key:
- Subkey:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
- Value name:
TcpMaxDataRetransmissions
- Value data:
5
(seconds)
TPC/IP Acknowledgements
TCP/IP can be the source of some significant remote method delays. You can increase TCP performance by immediately acknowledging incoming TCP segments, in all situations.To activate this feature, create the following key:
On Microsoft Windows 2000:
- Subkey:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\{Interface GUID}\
- Value name:
TcpDelAckTicks
- Value data:
0
On Microsoft Windows XP or Windows Server 2003:
- Subkey:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\{Interface GUID}
- Value name:
TcpAckFrequency
- Value data:
0
Links:
http://blogs.msdn.com/b/oldnewthing/archive/2006/02/22/536920.aspx
http://www.computerperformance.co.uk/windows7/windows7_delete_roaming_profile.htm
http://en.kioskea.net/faq/7106-windows-7-increase-the-performance-of-disk-cache
Keine Kommentare:
Kommentar veröffentlichen