From what I understand, Opus installs a system-wide hook for all file system events. The big advantage that we gain from this is that we can be sure that all listers are completely up-to-date at all times. However, this also has a certain impact of performance. The majority of filesystem events that occur are not directly relevant for Opus, yet each filesystem event will nevertheless incur a context switch to Opus's process, and these context switches can add up: each a context switch adds not just a few extra instructions, but rather many hundreds of instructions (and a user/kernel transition) to each filesystem event.
Now, as Leo has shown in the past (Thread count), on normal machines, the overall impact of the system-wide hook is barely noticeable. However, there are a couple of cases - which are becoming more and more common - in which I believe the impact is significant:
(1) Netbook users are generally pressed for processor cycles to begin with - netbooks are not built for performance, and processor cycles are at a premium. For these users, the extra cycles may well be an issue. Consider the following: if a netbook user runs Opus and then minimizes it, spending an hour in another application completely, over the course of that hour every single file transaction will be hooked and an extra context switch to Opus will be incurred. That is: just having Opus running in the background, without even switching to it once, will end up incurring a penalty of many extra processor cycles during the course of normal computer usage.
(2) Conversely, many machines these days come with upwards of 10 cores; but this also poses a problem, because users are now likely to run many file-intensive processes simultaneously. That is: although with single and dual-core machines users tended to do one thing at a time, leaving intense background tasks for overnight processing, multi-core machines have changed this situation. As an example, in one situation I needed to run an OCR program over some 50,000 documents. Previously I would have waited, but now, on our new 12-core machine, I simply ran it in the background, allowing it to use a couple of the cores, while I continued my usual work. The problem is, though, that Opus' system-wide hook now hooks into all of this activity simultaneously - all filesystem events from all 12 cores - and the cost is now palpable. As I noted in the aforementioned thread, under these conditions Opus' context switch count regularly hits 15,000 switches per second on my machine. I believe that anyone running multiple file-intensive processes on multiple cores will incur such an issue.
Fortunately, the good folks at Opus have provided us with the "no_external_change_notify" option (Prefs / Misc / Advanced), which turns off the system-wide hook completely. With this option in effect, Opus takes virtually no toll whatsoever on the system when it is not in the foreground. And, indeed, this is how I use Opus most of the time. The problem is that when this option is in effect, open listers don't refresh themselves ever, not even when they come into the foreground; they only refresh when the user performs a manual refresh. So, for instance, if I'm running my OCR program in the background, and from time to time I switch to an open OPUS lister to see any new files that have been output from the OCR, I won't see anything at all until I press "F5". From my experience, this is the solitary annoyance while running in the otherwise blissful "no_external_change_notify" mode.
In order to solve this, I've written an AutoHotKey script that takes care of specifically this issue. It installs a hook (not system-wide, but rather only for the dopus process), which is triggered anytime a new Opus window is brought to the foreground, at which point it performs a full refresh (GO refresh=all). As noted, the hook is limited to the specific Opus process, so when Opus is not in use, this hook won't ever be invoked, either. Here's the code:
[code]#Persistent
SetBatchLines,-1
HookProcAdr := RegisterCallback( "HookProc", "F" )
WinGet, OpusProcessID, PID, ahk_class dopus.lister
if OpusProcessID=
{
MsgBox Error: Opus is not Running
ExitApp
}
hWinEventHook := SetWinEventHook( 0x3, 0x3, 0, HookProcAdr, OpusProcessID, 0, 0 )
Return
HookProc( hWinEventHook, Event, hWnd, idObject, idChild, dwEventThread, dwmsEventTime )
{
Run "C:\Program Files\GPSoftware\Directory Opus\dopusrt.exe" /cmd Go REFRESH=all
}
SetWinEventHook(eventMin, eventMax, hmodWinEventProc, lpfnWinEventProc, idProcess, idThread, dwFlags)
{
DllCall("CoInitialize", Uint, 0)
return DllCall("SetWinEventHook", Uint,eventMin, Uint,eventMax, Uint,hmodWinEventProc, Uint,lpfnWinEventProc, Uint,idProcess , Uint,idThread, Uint,dwFlags)
}
[/code]
Note that the script must be run after Opus is already running (because it needs to first identify the process ID of the Opus process).