2 Copyright (C) 2009 Grame
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 #include "JackProfiler.h"
20 #include "JackServerGlobals.h"
21 #include "JackEngineControl.h"
22 #include "JackLockedEngine.h"
23 #include "JackArgParser.h"
30 JackProfilerClient::JackProfilerClient(jack_client_t
* client
, const char* name
)
33 char port_name
[JACK_CLIENT_NAME_SIZE
+ JACK_PORT_NAME_SIZE
];
34 fRefNum
= JackServerGlobals::fInstance
->GetEngine()->GetClientRefNum(name
);
36 snprintf(port_name
, sizeof(port_name
) - 1, "%s:scheduling", name
);
37 fSchedulingPort
= jack_port_register(client
, port_name
, JACK_DEFAULT_AUDIO_TYPE
, JackPortIsOutput
, 0);
39 snprintf(port_name
, sizeof(port_name
) - 1, "%s:duration", name
);
40 fDurationPort
= jack_port_register(client
, port_name
, JACK_DEFAULT_AUDIO_TYPE
, JackPortIsOutput
, 0);
43 JackProfilerClient::~JackProfilerClient()
45 jack_port_unregister(fClient
, fSchedulingPort
);
46 jack_port_unregister(fClient
, fDurationPort
);
50 JackProfiler::JackProfiler(jack_client_t
* client
, const JSList
* params
)
51 :fClient(client
), fLastMeasure(NULL
)
53 JackProfiler::JackProfiler(jack_client_t
* client
, const JSList
* params
)
57 jack_log("JackProfiler::JackProfiler");
59 fCPULoadPort
= fDriverPeriodPort
= fDriverEndPort
= NULL
;
62 const jack_driver_param_t
* param
;
63 for (node
= params
; node
; node
= jack_slist_next(node
)) {
64 param
= (const jack_driver_param_t
*)node
->data
;
66 switch (param
->character
) {
68 fCPULoadPort
= jack_port_register(client
, "cpu_load", JACK_DEFAULT_AUDIO_TYPE
, JackPortIsOutput
, 0);
72 fDriverPeriodPort
= jack_port_register(client
, "driver_period", JACK_DEFAULT_AUDIO_TYPE
, JackPortIsOutput
, 0);
76 fDriverEndPort
= jack_port_register(client
, "driver_end_time", JACK_DEFAULT_AUDIO_TYPE
, JackPortIsOutput
, 0);
81 // Resigster all running clients
82 const char **ports
= jack_get_ports(client
, NULL
, NULL
, 0);
84 for (int i
= 0; ports
[i
]; ++i
) {
85 std::string str
= std::string(ports
[i
]);
86 ClientRegistration(str
.substr(0, str
.find_first_of(':')).c_str(), 1, this);
91 jack_set_process_callback(client
, Process
, this);
92 jack_set_client_registration_callback(client
, ClientRegistration
, this);
93 jack_activate(client
);
96 JackProfiler::~JackProfiler()
98 jack_log("JackProfiler::~JackProfiler");
101 void JackProfiler::ClientRegistration(const char* name
, int val
, void *arg
)
104 JackProfiler
* profiler
= static_cast<JackProfiler
*>(arg
);
106 // Filter client or "system" name
107 if (strcmp(name
, jack_get_client_name(profiler
->fClient
)) == 0 || strcmp(name
, "system") == 0)
110 profiler
->fMutex
.Lock();
112 std::map
<std::string
, JackProfilerClient
*>::iterator it
= profiler
->fClientTable
.find(name
);
113 if (it
== profiler
->fClientTable
.end()) {
114 jack_log("Client %s added", name
);
115 profiler
->fClientTable
[name
] = new JackProfilerClient(profiler
->fClient
, name
);
118 std::map
<std::string
, JackProfilerClient
*>::iterator it
= profiler
->fClientTable
.find(name
);
119 if (it
!= profiler
->fClientTable
.end()) {
120 jack_log("Client %s removed", name
);
121 profiler
->fClientTable
.erase(it
);
122 delete((*it
).second
);
125 profiler
->fMutex
.Unlock();
129 int JackProfiler::Process(jack_nframes_t nframes
, void* arg
)
131 JackProfiler
* profiler
= static_cast<JackProfiler
*>(arg
);
133 if (profiler
->fCPULoadPort
) {
134 float* buffer_cpu_load
= (float*)jack_port_get_buffer(profiler
->fCPULoadPort
, nframes
);
135 float cpu_load
= jack_cpu_load(profiler
->fClient
);
136 for (unsigned int i
= 0; i
< nframes
; i
++) {
137 buffer_cpu_load
[i
] = cpu_load
/ 100.f
;
143 JackEngineControl
* control
= JackServerGlobals::fInstance
->GetEngineControl();
144 JackEngineProfiling
* engine_profiler
= &control
->fProfiler
;
145 JackTimingMeasure
* measure
= engine_profiler
->GetCurMeasure();
147 if (profiler
->fLastMeasure
&& profiler
->fMutex
.Trylock()) {
149 if (profiler
->fDriverPeriodPort
) {
150 float* buffer_driver_period
= (float*)jack_port_get_buffer(profiler
->fDriverPeriodPort
, nframes
);
151 float value1
= (float(measure
->fPeriodUsecs
) - float(measure
->fCurCycleBegin
- profiler
->fLastMeasure
->fCurCycleBegin
)) / float(measure
->fPeriodUsecs
);
152 for (unsigned int i
= 0; i
< nframes
; i
++) {
153 buffer_driver_period
[i
] = value1
;
157 if (profiler
->fDriverEndPort
) {
158 float* buffer_driver_end_time
= (float*)jack_port_get_buffer(profiler
->fDriverEndPort
, nframes
);
159 float value2
= (float(measure
->fPrevCycleEnd
- profiler
->fLastMeasure
->fCurCycleBegin
)) / float(measure
->fPeriodUsecs
);
160 for (unsigned int i
= 0; i
< nframes
; i
++) {
161 buffer_driver_end_time
[i
] = value2
;
165 std::map
<std::string
, JackProfilerClient
*>::iterator it
;
166 for (it
= profiler
->fClientTable
.begin(); it
!= profiler
->fClientTable
.end(); it
++) {
167 int ref
= (*it
).second
->fRefNum
;
168 long d5
= long(measure
->fClientTable
[ref
].fSignaledAt
- profiler
->fLastMeasure
->fCurCycleBegin
);
169 long d6
= long(measure
->fClientTable
[ref
].fAwakeAt
- profiler
->fLastMeasure
->fCurCycleBegin
);
170 long d7
= long(measure
->fClientTable
[ref
].fFinishedAt
- profiler
->fLastMeasure
->fCurCycleBegin
);
172 float* buffer_scheduling
= (float*)jack_port_get_buffer((*it
).second
->fSchedulingPort
, nframes
);
173 float value3
= float(d6
- d5
) / float(measure
->fPeriodUsecs
);
174 jack_log("Scheduling %f", value3
);
175 for (unsigned int i
= 0; i
< nframes
; i
++) {
176 buffer_scheduling
[i
] = value3
;
179 float* buffer_duration
= (float*)jack_port_get_buffer((*it
).second
->fDurationPort
, nframes
);
180 float value4
= float(d7
- d6
) / float(measure
->fPeriodUsecs
);
181 jack_log("Duration %f", value4
);
182 for (unsigned int i
= 0; i
< nframes
; i
++) {
183 buffer_duration
[i
] = value4
;
187 profiler
->fMutex
.Unlock();
189 profiler
->fLastMeasure
= measure
;
201 #include "driver_interface.h"
203 using namespace Jack
;
205 static Jack::JackProfiler
* profiler
= NULL
;
207 SERVER_EXPORT jack_driver_desc_t
* jack_get_descriptor()
209 jack_driver_desc_t
* desc
;
210 jack_driver_desc_filler_t filler
;
211 jack_driver_param_value_t value
;
213 desc
= jack_driver_descriptor_construct("profiler", JackDriverNone
, "real-time server profiling", &filler
);
216 jack_driver_descriptor_add_parameter(desc
, &filler
, "cpu-load", 'c', JackDriverParamBool
, &value
, NULL
, "Show DSP CPU load", NULL
);
217 jack_driver_descriptor_add_parameter(desc
, &filler
, "driver-period", 'p', JackDriverParamBool
, &value
, NULL
, "Show driver period", NULL
);
218 jack_driver_descriptor_add_parameter(desc
, &filler
, "driver-end-time", 'e', JackDriverParamBool
, &value
, NULL
, "Show driver end time", NULL
);
223 SERVER_EXPORT
int jack_internal_initialize(jack_client_t
* jack_client
, const JSList
* params
)
226 jack_info("profiler already loaded");
230 jack_log("Loading profiler");
232 profiler
= new Jack::JackProfiler(jack_client
, params
);
240 SERVER_EXPORT
int jack_initialize(jack_client_t
* jack_client
, const char* load_init
)
242 JSList
* params
= NULL
;
243 bool parse_params
= true;
245 jack_driver_desc_t
* desc
= jack_get_descriptor();
247 Jack::JackArgParser
parser ( load_init
);
248 if ( parser
.GetArgc() > 0 )
249 parse_params
= parser
.ParseParams ( desc
, ¶ms
);
252 res
= jack_internal_initialize ( jack_client
, params
);
253 parser
.FreeParams ( params
);
258 SERVER_EXPORT
void jack_finish(void* arg
)
260 Jack::JackProfiler
* profiler
= static_cast<Jack::JackProfiler
*>(arg
);
263 jack_log("Unloading profiler");