Quote Originally Posted by TheGreatCthulhu View Post
OK, let me see if I have the right idea here. (You're developing this in C++/CLI?)
Thanks for your qualified (as anticipated ) response, and yes, this is in C++/CLI.

For starters, I think, it may be helpful to see what we're talking about, to give some clarifying orientation. So here's an example screen shot of the tool we're talking about:

2012-11-18_013758.png

It shows a recording taken of another one of my own apps, an as-I-always-wanted-it sort of backup/file sync program, tracking CPU and memory utilization as well as disk throughput. The vertical red dotted lines are event marks (placed manually and the text annotations to them were entered manually as well, however, a feature of the EPM, no image manipulation ). It's a feature planned for later on that the program under test can place this sort of comments itself by means of an EPM adapter DLL that acts as a trace listener to the program under test, which is sort of science fiction by now, but an example of another sort of event mark source. The rest is more or less self-explanatory I think.

Your sample sources are classes designed to obtain data, timestamp it, porhaps queue it, and (I'm not sure about this one) raise .NET events? On the other hand, what you classified as event mark sources simply convey information that something has occurred (possibly including a way to identify the sender), and the semantics of the event will be "embedded" in the type of the event itself - something that lends itself naturally to the .NET event model.
Except some minor peculiarities of the timestamping mechanism, which can be considered implementation details from our current perspective, yes. In particular, you're right about the .NET-event-based nature of the event mark sources. Even the abstract interface I have defined for them declares such an event. And yes, this is pretty much by nature: The other currently implemented event mark source, the "event log watcher" (not shown in the screen shot) is based on the .NET framework's EventLog class and its EntryWritten event.

Now, consumers are either UI (various Views in MVP terminology), or objects which essentially (on a very conceptual level) take in a stream of events, and transform it into an output stream of different events, depending on some internal logic (I guess this encompasses both the triggers and the "operators")?
Yes. And that includes some comparatively abstract and minimalistic kind of consumer that merely consumes event marks and performs basic tasks like start/stop recording, play a sound, start an external process and the like.

In this context, triggers are actually a special case of event mark sources, while the "operators" would be specialized sample sources. Correct?
Yes, exactly that.

I guess that's an overview of the design, as it shows how different categories of classes interact, but I'd also like to know more about the interactions within the categories. Should various types of sample/event sources interact, and under what conditions?
To keep things "simple" () - remember, I'm planning a plug-in interface -, no, at least not from the perspective of my performance monitor app. With, of course, the exception of triggers and operators which fundamentally are defined as acting both as a consumer and source at the same time.

On the consumer side, how complicated is the UI, is there some tricky presentation logic involved, and how do you plan to sinc the UI with the data (are you maybe going for the MVP-based approach)?
Looking at the screen shot above, the chart control comprising the window's client area practically is the only consumer instance existing so far, while the frame window itself belongs to the yet-to-factor-out mediator. However, the chart is sort of a consumer with privileges: The source-related items on the chart have tool tips displaying information that probably will be available to any ordinary consumer as well, but they also feature context menus that allow things like deleting sources (including the respective data series), which is a direct manipulation of mediator-internal data structures that wouldn't be allowed to ordinary consumers.

Is there a need to support sample/event source switching at runtime, or show data from several sources simultaneously? Basically, what features you target?
Well, allowing just a single source to be displayed at a time would be quite boring, don't you think? And the user is allowed to add/remove items at runtime, with some restrictions applying to stored recordings. (I don't see much sense in adding new samples to recordings made days ago, for instance.) There's no plan to allow the items themselves to perform actions like that, however. (Sample sources can enter a "dead" state which allows to accommodate to things like processes being shut down while recording without the need to remove the entire source/data series or recording meaningless data.)

Admittedly it even took me quite some time to accommodate to the model-view (or document-view) architecture, and when it comes to MVC, the C functionality usually is somewhat scattered across the model and view classes (with some bias depending on the subject and my personal feel of it...). Let alone MVP...

For the triggers and the "operators", there's an opportunity to implement the Decorator pattern; a decorator wraps a source, adds a responsibility (filter/translate events), and passes the result along, itself becoming a source. [...]
Yeah, I remember a thread discussing that pattern, with you contributing and me just following IIRC... I'm used to envisioning this pattern as sort of a more flexible "Lego-style" design, while I see Mediator as a rather strictly circular design with exactly one vertex connecting the mediator with each colleague. While the concept of triggers and opeators seems to suggest a Decorator-like design, I think Mediator is possible here as well. That would put more responsibility (in particular dispatching/routing of information) on the mediator but may simplify the overall design outside that class. (Just as you said: There often is a trade-off between some possible patterns.)

When it comes to multithreading, making the shared objects immutable would simplify things a lot, if that's applicable to this scenario.
Yeah. I remember having called such a concept "fire-and-forget objects" in some forum thread, while that didn't actually require the objects to be strictly immutable. The requirement just was that the "firing" thread wouldn't use anything mutable it got from "outside" when constructing the said object, and wouldn't touch it anymore once it got deployed. The effect would more or less be the same and, yes, chances are that it would eliminate most of the synchronization needs I have now. Definitely worth consideration.

BTW, a comment to something you said: events are sequential in nature (for example, if you block inside an event handler in say, WinForms app, the whole thing freezes; only when the handler returns can the execution continue, and, eventually, can another event be fired).
You're right, of course. Technically, .NET events are strictly sequential, and what I actually meant was a sequential way of thinking. As an old-school guy who development-wise grew up in times when no-one even knew what multithreading is, I sometimes tend to confuse these things...

Can you say what do you intend to use multithreading for, specifically? Background processing tasks are good candidates, but if you're considering multiple threads for drawing, go instead for a game loop like, single threaded approach.
Actually, maybe an update loop based approach is not a bad idea overall for this type of application (of course, you could exploit the underlying windows msg loop in some way).
The reason why I introduced multithreading at all was that my program, after accumulating severall thousands of samples, tended to become a real CPU hog, mostly because of the activities of the Windows Forms chart control that doesn't seem to really have been made for things like that. I managed to reduce the overall CPU load imposed by my program to about the same amount that Process Explorer demands by a combination of two techniques I call "history downsampling" (displaying older samples as aggredated average data points while internally maintaining full temporal resolution) and "display rate throtteling" (adaptively, depending on the CPU load I cause myself, reducing the rate at which I update the chart control with respect to the actual sample rate). (Of course, Russinovich's tool achieves much more with the same count of CPU cycles... ) However, my program consumes its CPU load in quite fat bursts, with the chart control keeping the main thread busy for quite some time, eventually causing considerable distortion in the "sample time frame". I'm dodging this problem by doing the actual sampling in a separate thread, with this simple therad procedure (unmodified and uncommented), posting the sampling results to a thread-safe queue for the main thread to fetch them:

Code:
void Form1::SamplingThreadProc(Object ^objParams)
{
  SamplingThreadParams ^params = safe_cast<SamplingThreadParams ^>(objParams);
  int nSampleInterval = params->m_ist->SampleInterval * 1000;
  do {
    ScopedLock lock(params->m_ist->m_indicators);
    params->m_ist->TakeSampleSnapshot();
    for each (PerformanceIndicator ^ind in params->m_ist->m_indicators)
      if (ind->CurrentSnapshotSample && (!ind->Delta || ind->LastSnapshotSample))
        params->m_cquPointQueue->Enqueue(gcnew DataPointQueueEntry(ind));
  } while (!params->m_evtShutdown->WaitOne(nSampleInterval));
}
You also said you'd like both event-based notification and polling; what are your current ideas about approaching that?
The idea behind this originates from the "display rate throtteling" mechanism: While the chart display consumer, in order to reduce CPU load, may decide to just poll the accumulated sample data every, say, four or eight seconds, an "emergency response" consumer that starts an external process or plays a sound may need the sample data as soon as it arrives. However, I'm not yet sure about the concrete implementation. Currently I'm considering a scheme where a consumer can issue a preference for either push or pull operation, which the mediator may or may not honor.

Finally, about the Mediator patten: basically, a mediator object is, as you said, a hub of sorts through which all interaction goes within a system; it encapsulates interaction rules for the (many) components of the system (contrast with Facade which provides an interface to a system; an interface for the client code to use). Introducing a mediator (which can be a somewhat ugly, complicated class) in turn enables the components of the system to be reused far more easily (as many dependencies are reduced to one (or few)). The other thing is that the system logic that would otherwise be distributed among all the components is now made more explicit, and moved into the mediator itself; this means that it is now possible to alter this behavior by subclassing only one class - the mediator, if something like that is required. [...]
This seems to match something I said some paragraphs above: Using a mediator "(which can be a somewhat ugly, complicated class)" may put more responsibility on just that class, while in exchange significantly simplifying the outside design.