Module: environment-protocols Synopsis: Environment profiling protocols Author: Andy Armstrong Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: Functional Objects Library Public License Version 1.0 Dual-license: GNU Lesser General Public License Warranty: Distributed WITHOUT WARRANTY OF ANY KIND define constant = one-of(#"interval", #"allocation", #"breakpoints"); define class () sealed slot profile-state-profiling-enabled? :: = #f; sealed slot profile-state-default-options :: false-or() = #f; sealed slot profile-state-current-options :: false-or() = #f; sealed slot profile-state-last-profile :: false-or() = #f; end class ; define open generic profile-snapshot-available-values (server :: ) => (values :: ); define open generic start-profiling-application (server :: , #key options :: false-or()) => (); define open generic stop-profiling-application (server :: ) => (profile :: false-or()); define open generic process-profiling-results (application :: ) => (profile :: false-or()); define method profiling-enabled? (server :: ) => (enabled? :: ) let project = server.server-project; project.project-profile-state.profile-state-profiling-enabled? end method profiling-enabled?; define method project-default-profile-options (project :: ) => (options :: false-or()) project.project-profile-state.profile-state-default-options end method project-default-profile-options; define method project-default-profile-options-setter (options :: false-or(), project :: ) => (options :: false-or()) project.project-profile-state.profile-state-default-options := options end method project-default-profile-options-setter; define method project-last-profile (project :: ) => (profile :: false-or()) let application = project.project-application; let profile-state = project.project-profile-state; if (application & project.profiling-enabled?) profile-state.profile-state-last-profile := process-profiling-results(application) else profile-state.profile-state-last-profile end end method project-last-profile; define class () sealed constant slot profile-sampling-style :: , required-init-keyword: style:; sealed constant slot profile-sampling-rate :: false-or() = #f, init-keyword: rate:; end class ; define class () sealed constant slot profile-snapshot-values :: , required-init-keyword: values:; sealed constant slot profile-snapshot-stack-depth :: false-or() = #f, init-keyword: stack-depth:; end class ; define class () sealed constant slot profile-sampling-options :: , required-init-keyword: sampling-options:; sealed constant slot profile-snapshot-options :: , required-init-keyword: snapshot-options:; end class ; define open abstract class () constant sealed slot application-profile-options :: , required-init-keyword: options:; constant sealed slot application-profile-snapshots :: = make(); constant sealed slot application-profile-threads :: = make(); sealed slot application-total-wall-time :: = 0; sealed slot application-total-page-faults :: = 0; end class ; define open abstract class () sealed constant slot application-snapshot-wall-time :: false-or(), required-init-keyword: wall-time:; sealed constant slot application-snapshot-page-faults :: false-or(), required-init-keyword: page-faults:; sealed constant slot application-snapshot-thread-snapshots :: , required-init-keyword: thread-snapshots:; end class ; define open abstract class () sealed constant slot thread-snapshot-thread :: , required-init-keyword: thread:; sealed constant slot thread-snapshot-cpu-time :: false-or(), required-init-keyword: cpu-time:; sealed constant slot thread-snapshot-allocated-class :: false-or(), required-init-keyword: allocated-class:; sealed constant slot thread-snapshot-allocation :: false-or(), required-init-keyword: allocation:; sealed slot %snapshots :: false-or() = #f; end class ; define open abstract class () constant sealed slot frame-snapshot-function :: false-or(), required-init-keyword: function:; constant sealed slot frame-snapshot-source-location :: false-or(), required-init-keyword: source-location:; end class ; define open generic application-profile-options (profile :: ) => (options :: ); define open generic thread-snapshot-stack-size (application :: , snapshot :: ) => (size :: ); define open generic process-thread-snapshot-frame-snapshots (application :: , snapshot :: ) => (frame-snapshots :: ); /// Project dispatching methods define method start-profiling-application (project :: , #key options :: false-or() = #f) => () let state = project.project-profile-state; let options = options | state.profile-state-default-options; assert(~state.profile-state-profiling-enabled?, "Attempting to start profiling when it is already enabled"); let application = project.project-application; state.profile-state-current-options := options; state.profile-state-profiling-enabled? := #t; application & ensure-profiling-started(application); broadcast($project-channel, make(, project: project, enabled?: #t)) end method start-profiling-application; define function ensure-profiling-started (application :: ) => () let project = application.server-project; let state = project.project-profile-state; let options = state.profile-state-current-options; start-profiling-application(application, options: options) end function ensure-profiling-started; define method stop-profiling-application (project :: ) => (profile :: false-or()) let state = project.project-profile-state; assert(state.profile-state-profiling-enabled?, "Attempting to stop profiling when it is already stopped"); block () let application = project.project-application; if (application) state.profile-state-last-profile := stop-profiling-application(application) else state.profile-state-last-profile end cleanup state.profile-state-profiling-enabled? := #f; broadcast($project-channel, make(, project: project, enabled?: #f)) end end method stop-profiling-application; define method clear-profiling-results (server :: ) => () let project = server.server-project; let state = project.project-profile-state; assert(~profiling-enabled?(project), "Attempting to clear profiling results while profiling is active"); state.profile-state-last-profile := #f end method clear-profiling-results; define method profile-snapshot-available-values (project :: ) => (values :: ) let application = project.project-application; assert(application, "Attempting to query snapshot values with no application!"); profile-snapshot-available-values(application) end method profile-snapshot-available-values; /// Some convenience functions built on these protocols define inline function application-total-snapshots (profile :: ) => (total :: ) profile.application-profile-snapshots.size end function application-total-snapshots; define inline function do-application-profile-snapshots (function :: , profile :: ) => () do(function, profile.application-profile-snapshots) end function do-application-profile-snapshots; define inline function do-application-profile-threads (function :: , profile :: ) => () do(function, profile.application-profile-threads) end function do-application-profile-threads; define function application-snapshot-thread-snapshot (snapshot :: , thread :: ) => (thread-snapshot :: false-or()) let snapshots = snapshot.application-snapshot-thread-snapshots; block (return) for (thread-snapshot :: in snapshots) if (thread-snapshot.thread-snapshot-thread == thread) return(thread-snapshot) end end; #f end end function application-snapshot-thread-snapshot; define inline function do-application-snapshot-thread-snapshots (function :: , snapshot :: ) => () do(function, snapshot.application-snapshot-thread-snapshots) end function do-application-snapshot-thread-snapshots; define function do-thread-profile-snapshots (function :: , application :: , profile :: , thread :: ) => (threads :: ) let snapshots :: = make(); do-application-profile-snapshots (method (application-snapshot :: ) let thread-snapshot = application-snapshot-thread-snapshot(application-snapshot, thread); if (thread-snapshot) function(application-snapshot, thread-snapshot) end end, profile); snapshots end function do-thread-profile-snapshots; define function thread-profile-snapshots (application :: , profile :: , thread :: ) => (threads :: ) let snapshots :: = make(); do-thread-profile-snapshots (method (snapshot :: ) add!(snapshots, snapshot) end, application, profile, thread); snapshots end function thread-profile-snapshots; define function thread-snapshot-frame-snapshots (application :: , snapshot :: ) => (snapshots :: ) snapshot.%snapshots | begin let snapshots = process-thread-snapshot-frame-snapshots(application, snapshot); snapshot.%snapshots := snapshots end end function thread-snapshot-frame-snapshots; define function do-thread-snapshot-functions (function :: , application :: , snapshot :: ) => () let frame-snapshots = thread-snapshot-frame-snapshots(application, snapshot); for (frame-snapshot :: in frame-snapshots) function(frame-snapshot.frame-snapshot-function, frame-snapshot.frame-snapshot-source-location) end end function do-thread-snapshot-functions; define function thread-snapshot-functions (application :: , snapshot :: ) => (functions :: ) map(frame-snapshot-function, thread-snapshot-frame-snapshots(application, snapshot)) end function thread-snapshot-functions;