Skip to main content
Engineering LibreTexts

16.10: How MessageTally is Implemented?

  • Page ID
    46432
  • \( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \) \( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)\(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\) \(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\)\(\newcommand{\AA}{\unicode[.8,0]{x212B}}\)

    MessageTally is a gorgeous example on how to use Pharo’s reflecting capabilities. The method spyEvery: millisecs on: aBlock contains the whole profiling logic. This method is indirectly called by spyOn:. The millisecs value is the amount of milliseconds between each sample. It is set at 1 per default. The block to be profiled is aBlock.

    The essence of the profiling activity is given by the following code excerpt:

    observedProcess := Processor activeProcess.
    Timer := [
        [ true ] whileTrue: [
            | startTime |
            startTime := Time millisecondClockValue.
            myDelay wait.
            self
                tally: Processor preemptedProcess suspendedContext
                in: (observedProcess == Processor preemptedProcess
                    ifTrue: [ observedProcess ] ifFalse: [ nil ])
                by: (Time millisecondClockValue - startTime) // millisecs ].
        nil] newProcess.
    Timer priority: Processor timingPriority-1.
    

    Timer is a new process, set at a high priority, that is in charge of monitoring aBlock. The process scheduler will therefore favorably active it (timingPriority is the process priority of system processes). It creates an infinite loop that waits for the amount of necessary milliseconds (myDelay) before snapshooting the method call stack. The process to observe is observedProcess. It is the process in which the message spyEvery: millisecs on: aBlock has been sent.

    The idea of profiling is to associate to each method context a counter. This association is realized with an instance of the class MessageTally (the class defines the variables class, method and process).

    At a regular interval (myDelay), the counter of each stack frame is incremented with the amount of elapsed milliseconds. The stack frame is obtained by sending suspendedContext to the process that has just been preempted.

    The method tally: context in: aProcess by: count increments each stack frame by the amount of milliseconds given by count.

    The memory statistic are given by differentiating the amount of consumed memory, before and after the profiling. Smalltalk, an instance of the class SmalltalkImage, contains many accessing methods to query the amount of available memory.


    This page titled 16.10: How MessageTally is Implemented? is shared under a CC BY-SA 3.0 license and was authored, remixed, and/or curated by Alexandre Bergel, Damien Cassou, Stéphane Ducasse, Jannik Laval (Square Bracket Associates) via source content that was edited to the style and standards of the LibreTexts platform; a detailed edit history is available upon request.