1/*
2 * Copyright (C) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import { KeyPathStruct } from '../../bean/KeyPathStruct';
17import { CpuStruct } from '../ui-worker/cpu/ProcedureWorkerCPU';
18import { query } from '../SqlLite';
19import { CpuUsage, Freq } from '../../bean/CpuUsage';
20import { Counter } from '../../bean/BoxSelection';
21import { CpuFreqStruct } from '../ui-worker/ProcedureWorkerFreq';
22import { CpuFreqLimitsStruct } from '../ui-worker/cpu/ProcedureWorkerCpuFreqLimits';
23import { CpuFreqRowLimit } from '../../component/chart/SpFreqChart';
24import { Utils } from '../../component/trace/base/Utils';
25
26export const queryCpuKeyPathData = (threads: Array<KeyPathStruct>): Promise<Array<CpuStruct>> => {
27  const sqlArray: Array<string> = [];
28  sqlArray.push(' 1 = 0');
29  for (const thread of threads) {
30    sqlArray.push(` or  (tid = ${thread.tid} and ts in (${thread.tsArray}))`);
31  }
32  let sql = sqlArray.join(' ');
33  return query(
34    'queryCpuKeyPathData',
35    `SELECT B.pid as processId,
36        B.cpu,
37        B.tid,
38        B.itid  as id,
39        B.dur  AS dur,
40        B.ts - T.start_ts  AS startTime,
41        B.arg_setid   as argSetID,
42        1 as isKeyPath
43    from thread_state AS B
44    left join trace_range as T
45    where ${sql}`
46  );
47};
48
49export const getTabCpuUsage = (cpus: Array<number>, leftNs: number, rightNs: number,
50  traceId?: string): Promise<Array<CpuUsage>> =>
51  query<CpuUsage>(
52    'getTabCpuUsage',
53    `
54    select
55      cpu,
56      sum(case
57        when (A.ts - B.start_ts) < $leftNS
58          then (A.ts - B.start_ts + A.dur - $leftNS)
59        when (A.ts - B.start_ts) >= $leftNS
60          and (A.ts - B.start_ts + A.dur) <= $rightNS
61          then A.dur
62        when (A.ts - B.start_ts + A.dur) > $rightNS
63          then ($rightNS - (A.ts - B.start_ts)) end) / cast($rightNS - $leftNS as float) as usage
64    from
65      thread_state A,
66      trace_range B
67    where
68      (A.ts - B.start_ts) > 0 and A.dur > 0
69    and
70      cpu in (${cpus.join(',')})
71    and
72      (A.ts - B.start_ts + A.dur) > $leftNS
73    and
74      (A.ts - B.start_ts) < $rightNS
75    group by
76      cpu`,
77    { $leftNS: leftNs, $rightNS: rightNs },
78    { traceId: traceId }
79  );
80
81export const getTabCpuFreq = (cpus: Array<number>, leftNs: number, rightNs: number,
82  traceId?: string): Promise<Array<Freq>> =>
83  query<Freq>(
84    'getTabCpuFreq',
85    `
86    select
87      cpu,
88      value,
89      (ts - tr.start_ts) as startNs
90    from
91      measure m,
92      trace_range tr
93    inner join
94      cpu_measure_filter t
95    on
96      m.filter_id = t.id
97    where
98      (name = 'cpufreq' or name='cpu_frequency')
99    and
100      cpu in (${cpus.join(',')})
101    and
102      startNs > 0
103    and
104      startNs < $rightNS
105    --order by startNs
106    `,
107    { $leftNS: leftNs, $rightNS: rightNs },
108    { traceId: traceId }
109  );
110
111export const getTabCounters = (
112  processFilterIds: Array<number>,
113  virtualFilterIds: Array<number>,
114  startTime: number
115): //@ts-ignore
116Promise<unknown> => {
117  let processSql = `select
118        t1.filter_id as trackId,
119        t2.name,
120        value,
121        t1.ts - t3.start_ts as startTime
122      from
123        process_measure t1
124      left join
125        process_measure_filter t2
126      on
127        t1.filter_id = t2.id
128      left join
129        trace_range t3
130      where
131        filter_id in (${processFilterIds.join(',')})
132      and
133        startTime <= ${startTime}`;
134  let virtualSql = `select
135        t1.filter_id as trackId,
136        t2.name,
137        value,
138        t1.ts - t3.start_ts as startTime
139      from
140        sys_mem_measure t1
141      left join
142        sys_event_filter t2
143      on
144        t1.filter_id = t2.id
145      left join
146        trace_range t3
147      where
148        filter_id in (${virtualFilterIds.join(',')})
149      and
150        startTime <= ${startTime}`;
151  let sql = '';
152  if (processFilterIds.length > 0 && virtualFilterIds.length > 0) {
153    sql = `${processSql} union ${virtualSql}`;
154  } else {
155    if (processFilterIds.length > 0) {
156      sql = processSql;
157    } else {
158      sql = virtualSql;
159    }
160  }
161  return query<Counter>('getTabCounters', sql, {});
162};
163export const getTabCpuByProcess = (
164  cpus: Array<number>,
165  leftNS: number,
166  rightNS: number,
167  traceId?: string
168): //@ts-ignore
169Promise<unknown[]> => //@ts-ignore
170  query<unknown>(
171    'getTabCpuByProcess',
172    `
173    select
174      B.pid as pid,
175      sum(iif(B.dur = -1 or B.dur is null, 0, B.dur)) as wallDuration,
176      avg(iif(B.dur = -1 or B.dur is null, 0, B.dur)) as avgDuration,
177      count(B.tid) as occurrences
178    from
179      thread_state AS B
180    left join
181      trace_range AS TR
182    where
183      B.cpu in (${cpus.join(',')})
184    and
185      not ((B.ts - TR.start_ts + iif(B.dur = -1 or B.dur is null, 0, B.dur) < $leftNS) 
186      or (B.ts - TR.start_ts > $rightNS ))
187    group by
188      B.pid
189    order by
190      wallDuration desc;`,
191    { $rightNS: rightNS, $leftNS: leftNS },
192    { traceId: traceId }
193  );
194
195export const getTabCpuByThread = (cpus: Array<number>, leftNS: number, rightNS: number,
196  traceId?: string): Promise<unknown[]> =>
197  query<unknown>(
198    'getTabCpuByThread',
199    `
200    select
201      TS.pid as pid,
202      TS.tid as tid,
203      TS.cpu,
204      sum( min(${rightNS},(TS.ts - TR.start_ts + iif(TS.dur = -1 or TS.dur is null, 0, TS.dur))) - 
205      max(${leftNS},TS.ts - TR.start_ts)) wallDuration,
206      count(TS.tid) as occurrences
207    from
208      thread_state AS TS
209    left join
210      trace_range AS TR
211    where
212      TS.cpu in (${cpus.join(',')})
213    and
214      not ((TS.ts - TR.start_ts + iif(TS.dur = -1 or TS.dur is null, 0, TS.dur) < $leftNS) 
215      or (TS.ts - TR.start_ts > $rightNS))
216    group by
217      TS.cpu,
218      TS.pid,
219      TS.tid
220    order by
221      wallDuration desc;`,
222    { $rightNS: rightNS, $leftNS: leftNS },
223    { traceId: traceId }
224  );
225
226export const queryCpuData = (cpu: number, startNS: number, endNS: number): Promise<Array<CpuStruct>> =>
227  query(
228    'queryCpuData',
229    `
230    SELECT
231    B.pid as processId,
232    B.cpu,
233    B.tid,
234    B.itid as id,
235    B.dur,
236    B.ts - TR.start_ts AS startTime,
237    B.arg_setid as argSetID
238from thread_state AS B
239    left join trace_range AS TR
240where B.itid is not null
241    and
242      B.cpu = $cpu
243    and
244      startTime between $startNS and $endNS;`,
245    {
246      $cpu: cpu,
247      $startNS: startNS,
248      $endNS: endNS,
249    }
250  );
251
252export const queryCpuFreq = (traceId?: string): Promise<Array<{ cpu: number; filterId: number }>> =>
253  query(
254    'queryCpuFreq',
255    `
256    select
257      cpu,id as filterId
258    from
259      cpu_measure_filter
260    where
261      (name='cpufreq' or name='cpu_frequency')
262    order by cpu;
263    `, {}, { traceId: traceId }
264  );
265
266export const queryCpuFreqData = (cpu: number): Promise<Array<CpuFreqStruct>> =>
267  query<CpuFreqStruct>(
268    'queryCpuFreqData',
269    `
270    select
271      cpu,
272      value,
273      ifnull(dur,tb.end_ts - c.ts) dur,
274      ts-tb.start_ts as startNS
275    from
276      measure c,
277      trace_range tb
278    inner join
279      cpu_measure_filter t
280    on
281      c.filter_id = t.id
282    where
283      (name = 'cpufreq' or name='cpu_frequency')
284    and
285      cpu= $cpu
286    --order by ts;
287    `,
288    { $cpu: cpu }
289  );
290
291export const queryCpuMax = (traceId?: string): //@ts-ignore
292Promise<Array<unknown>> =>
293  query(
294    'queryCpuMax',
295    `
296    select
297      cpu
298    from
299      sched_slice
300    order by
301      cpu
302    desc limit 1;`,
303    {},
304    { traceId: traceId }
305  );
306
307export const queryCpuDataCount = (): Promise<unknown[]> =>
308  query('queryCpuDataCount',
309    'select count(1) as count,cpu from thread_state where cpu not null group by cpu');
310
311export const queryCpuCount = (traceId?: string): //@ts-ignore
312Promise<Array<unknown>> =>
313  query(
314    'queryCpuCount',
315    `
316   select max(cpuCount) cpuCount from
317(select ifnull((max(cpu) + 1),0) cpuCount  from cpu_measure_filter where name in ('cpu_frequency','cpu_idle')
318 union all
319 select ifnull((max(callid)+1),0) cpuCount from irq
320) A;`,
321    {},
322    { traceId: traceId }
323  );
324
325export const queryCpuSchedSlice = async (traceId?: string): Promise<Array<unknown>> => {
326  let cpuSchedSliceBuffer = await query(
327    'queryCpuSchedSlice',
328    `select 
329      (ts - start_ts) as ts,
330       itid,
331       end_state as endState,
332       priority
333    from
334      sched_slice,
335      trace_range;`,
336    {},
337    { traceId: traceId, action: 'exec-buf' }
338  );
339  // @ts-ignore
340  return Utils.convertJSON(cpuSchedSliceBuffer);
341};
342
343export const queryCpuStateFilter = (traceId?: string):
344Promise<Array<{ cpu: number; filterId: number }>> =>
345  query(
346    'queryCpuStateFilter',
347    `select cpu,id as filterId 
348    from cpu_measure_filter 
349    where name = 'cpu_idle' order by cpu;`,
350    {},
351    { traceId: traceId }
352  );
353
354export const queryCpuState = (
355  cpuFilterId: number
356): //@ts-ignore
357Promise<Array<unknown>> =>
358  query(
359    'queryCpuState',
360    `
361        select (A.ts - B.start_ts) as startTs,ifnull(dur,B.end_ts - A.ts) dur,
362            value
363        from measure A,trace_range B
364        where filter_id = $filterId;`,
365    { $filterId: cpuFilterId }
366  );
367
368export const queryCpuMaxFreq = (traceId?: string):
369Promise<Array<{
370  maxFreq: number
371}>> =>
372  query(
373    'queryCpuMaxFreq',
374    `
375    select
376      max(value) as maxFreq
377    from
378      measure c
379    inner join
380      cpu_measure_filter t
381    on
382      c.filter_id = t.id
383    where
384      (name = 'cpufreq' or name='cpu_frequency');`, {}, { traceId: traceId }
385  );
386
387export const queryTraceCpu = (): Promise<
388  Array<{
389    tid: string;
390    pid: string;
391    cpu: string;
392    dur: string;
393    min_freq: string;
394    max_freq: string;
395    avg_frequency: string;
396  }>
397> =>
398  query(
399    'queryTraceCpu',
400    `SELECT 
401        itid AS tid, 
402        ipid AS pid, 
403        group_concat(cpu, ',') AS cpu, 
404        group_concat(dur, ',') AS dur, 
405        group_concat(min_freq, ',') AS min_freq, 
406        group_concat(max_freq, ',') AS max_freq, 
407        group_concat(avg_frequency, ',') AS avg_frequency 
408        FROM 
409        (SELECT 
410            itid, 
411            ipid, 
412            cpu, 
413            CAST (SUM(dur) AS INT) AS dur, 
414            CAST (MIN(freq) AS INT) AS min_freq, 
415            CAST (MAX(freq) AS INT) AS max_freq, 
416            CAST ( (SUM(dur * freq) / SUM(dur) ) AS INT) AS avg_frequency 
417            from 
418            result 
419            group by 
420            itid, cpu
421        ) 
422        GROUP BY 
423        ipid, itid 
424        ORDER BY 
425        ipid
426    `
427  );
428
429export const queryTraceCpuTop = (): Promise<
430  Array<{
431    tid: string;
432    pid: string;
433    cpu: string;
434    duration: string;
435    min_freq: string;
436    max_freq: string;
437    avg_frequency: string;
438    sumNum: string;
439  }>
440> =>
441  query(
442    'queryTraceCpuTop',
443    `SELECT
444         ipid AS pid,
445         itid AS tid, 
446        group_concat(cpu, ',') AS cpu, 
447        group_concat(dur, ',') AS dur,
448        group_concat(avg_frequency, ',') AS avg_frequency,
449        group_concat(min_freq, ',') AS min_freq, 
450        group_concat(max_freq, ',') AS max_freq, 
451        sum(dur * avg_frequency) AS sumNum 
452        FROM 
453        (SELECT 
454            itid, 
455            ipid, 
456            cpu, 
457            CAST (SUM(dur) AS INT) AS dur, 
458            CAST (MIN(freq) AS INT) AS min_freq, 
459            CAST (MAX(freq) AS INT) AS max_freq, 
460            CAST ( (SUM(dur * freq) / SUM(dur) ) AS INT) AS avg_frequency 
461            from result group by itid, cpu
462        ) 
463        GROUP BY 
464        ipid, itid 
465        ORDER BY 
466        sumNum 
467        DESC 
468        LIMIT 10;
469    `
470  );
471
472export const queryCpuFreqUsageData = (
473  Ids: Array<number>
474): Promise<
475  Array<{
476    startNS: number;
477    filter_id: number;
478    value: number;
479    dur: number;
480  }>
481> =>
482  query(
483    'queryCpuFreqUsageData',
484    `select
485          value,
486          ifnull(dur,tb.end_ts - c.ts) dur,
487          ts-tb.start_ts as startNS,
488          filter_id
489        from
490          measure c,
491          trace_range tb
492        where
493          c.filter_id in (${Ids.join(',')})
494       `,
495    {},
496    { traceId: Utils.currentSelectTrace }
497  );
498
499export const queryCpuFreqFilterId = (): Promise<
500  Array<{
501    id: number;
502    cpu: number;
503  }>
504> =>
505  query(
506    'queryCpuFreqFilterId',
507    `
508        select
509          id,
510          cpu
511        from
512          cpu_measure_filter 
513        where
514          name='cpufreq'
515        or
516          name='cpu_frequency'
517     `,
518    {},
519    { traceId: Utils.currentSelectTrace }
520  );
521
522export const searchCpuData = (
523  keyword: string
524): //@ts-ignore
525Promise<Array<unknown>> => {
526  let id = parseInt(keyword);
527  let sql = `
528  select B.pid                        as processId,
529       B.cpu,
530       B.tid,
531       'cpu'                          as type,
532       B.itid                         as id,
533       B.dur                          as dur,
534       B.ts - TR.start_ts             as startTime,
535       B.arg_setid                    as argSetID
536from thread_state AS B, trace_range TR
537         left join process p on B.pid = p.pid
538         left join thread t on B.itid = t.itid
539where B.cpu not null and B.ts between TR.start_ts and TR.end_ts 
540  and (
541        t.name like '%${keyword}%'
542        or B.tid = ${Number.isNaN(id) ? -1 : id}
543        or B.pid = ${Number.isNaN(id) ? -1 : id}
544        or p.name like '%${keyword}%'
545    )
546order by startTime;`;
547  return query('searchCpuData', sql, {});
548};
549
550export const getTabPaneCounterSampleData = (
551  leftNs: number,
552  rightNs: number,
553  cpuStateFilterIds: Array<number>
554): //@ts-ignore
555Promise<Array<unknown>> => {
556  let str = '';
557  if (cpuStateFilterIds.length > 0) {
558    str = ` and filter_id in (${cpuStateFilterIds.join(',')})`;
559  }
560  return query(
561    'getTabPaneCounterSampleData',
562    `
563    select value, filter_id as filterId, ts, f.cpu
564    from measure left join cpu_measure_filter as f on f.id=filter_id
565    where
566    ts <= $rightNs${str} order by ts asc;
567`,
568    { $leftNs: leftNs, $rightNs: rightNs }, {traceId: Utils.currentSelectTrace}
569  );
570};
571export const queryJsCpuProfilerConfig = (): //@ts-ignore
572Promise<Array<unknown>> =>
573  query('queryJsCpuProfilerConfig',
574    'SELECT pid, type, enable_cpu_Profiler as enableCpuProfiler FROM js_config');
575
576export const queryJsCpuProfilerData = (): //@ts-ignore
577Promise<Array<unknown>> => query('queryJsCpuProfilerData',
578  'SELECT 1 WHERE EXISTS(select 1 from js_cpu_profiler_node)');
579
580export const querySystemCallsTop = (): Promise<
581  Array<{
582    tid: string;
583    pid: string;
584    funName: string;
585    frequency: string;
586    minDur: string;
587    maxDur: string;
588    avgDur: string;
589  }>
590> =>
591  query(
592    'querySystemCallsTop',
593    `SELECT 
594        cpu.tid AS tid, 
595        cpu.pid AS pid, 
596        callstack.name AS funName, 
597        count(callstack.name) AS frequency, 
598        min(callstack.dur) AS minDur, 
599        max(callstack.dur) AS maxDur, 
600        round(avg(callstack.dur)) AS avgDur 
601        FROM 
602        callstack 
603        INNER JOIN 
604        (SELECT 
605            itid AS tid, 
606            ipid AS pid, 
607            group_concat(cpu, ',') AS cpu, 
608            group_concat(dur, ',') AS dur, 
609            group_concat(min_freq, ',') AS min_freq, 
610            group_concat(max_freq, ',') AS max_freq, 
611            group_concat(avg_frequency, ',') AS avg_frequency, 
612            sum(dur * avg_frequency) AS sumNum 
613            FROM 
614            (SELECT 
615                itid, 
616                ipid, 
617                cpu, 
618                CAST (SUM(dur) AS INT) AS dur, 
619                CAST (MIN(freq) AS INT) AS min_freq, 
620                CAST (MAX(freq) AS INT) AS max_freq, 
621                CAST ( (SUM(dur * freq) / SUM(dur) ) AS INT) AS avg_frequency 
622                FROM 
623                result 
624                GROUP BY 
625                itid, cpu
626            ) 
627            GROUP BY 
628            ipid, itid 
629            ORDER BY 
630            sumNum 
631            DESC 
632            LIMIT 10
633        ) AS cpu 
634        ON 
635        callstack.callid = cpu.tid 
636        GROUP BY 
637        callstack.name 
638        ORDER BY 
639        frequency 
640        DESC
641    LIMIT 10`
642  );
643
644export const queryWakeupListPriority = (
645  itid: number[],
646  ts: number[],
647  cpus: number[]
648): //@ts-ignore
649Promise<Array<unknown>> =>
650  query(
651    'queryWakeupListPriority',
652    `
653    select itid, priority, (ts - start_ts) as ts, dur, cpu
654    from sched_slice,trace_range where cpu in (${cpus.join(',')})
655    and itid in (${itid.join(',')})
656    and ts - start_ts in (${ts.join(',')})
657    `,
658    {},
659    { traceId: Utils.currentSelectTrace }
660  );
661
662export const getCpuLimitFreqBoxSelect = (
663  arr: Array<{
664    maxFilterId: string;
665    minFilterId: string;
666    cpu: string;
667  }>,
668  rightNS: number
669): //@ts-ignore
670Promise<Array<unknown>> => {
671  let ids = [];
672  let condition = `(case`;
673  for (let item of arr) {
674    condition = `${condition} when filter_id in (${item.maxFilterId}, ${item.minFilterId}) then ${item.cpu}`;
675    ids.push(item.maxFilterId, item.minFilterId);
676  }
677  condition = `${condition} else -1 end) as cpu`;
678  let sql = `
679  select 
680    ts - T.start_ts as startNs,
681    dur,
682    max(value) as max,
683    min(value) as min,
684    ${condition}
685  from measure,trace_range T 
686  where filter_id in (${ids.join(',')})
687    and ts - T.start_ts < ${rightNS} 
688  group by ts
689  `;
690  return query('getCpuLimitFreqBoxSelect', sql, {}, {traceId: Utils.currentSelectTrace});
691};
692
693export const getCpuLimitFreq = (maxId: number, minId: number, cpu: number):
694  Promise<Array<CpuFreqLimitsStruct>> =>
695  query(
696    'getCpuLimitFreq',
697    `
698    select ts - T.start_ts as startNs,
699           dur,
700           max(value) as max,
701           min(value) as min,
702            $cpu as cpu 
703    from measure,trace_range T where filter_id in ($maxId,$minId) group by ts
704`,
705    { $maxId: maxId, $minId: minId, $cpu: cpu }
706  );
707
708export const getCpuLimitFreqId = (traceId?: string): Promise<Array<CpuFreqRowLimit>> =>
709  query(
710    'getCpuMaxMinFreqId',
711    `
712    select 
713    cpu,
714    MAX(iif(name = 'cpu_frequency_limits_max',id,0)) as maxFilterId,
715    MAX(iif(name = 'cpu_frequency_limits_min',id,0)) as minFilterId 
716    from cpu_measure_filter 
717    where name in ('cpu_frequency_limits_max','cpu_frequency_limits_min') group by cpu
718`,
719    {},
720    { traceId: traceId }
721  );
722
723export const getCpuLimitFreqMax = (
724  filterIds: string,
725  traceId?: string
726): Promise<Array<{ maxValue: number; filterId: number }>> => {
727  return query(
728    'getCpuLimitFreqMax',
729    `
730    select max(value) as maxValue,filter_id as filterId 
731    from measure where filter_id in (${filterIds}) group by filter_id
732`,
733    {},
734    { traceId: traceId }
735  );
736};
737