1// Copyright (c) 2021 Huawei Device Co., Ltd.
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6//     http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14import { Args } from '../CommonArgs';
15import { TraficEnum } from '../utils/QueryEnum';
16
17export const chartHiperfProcessData10MSProtoSql = (args: Args): string => {
18  return `select startNS as startNS,
19                 max(event_count)                                                         eventCount,
20                 sample_count as sampleCount,
21                 event_type_id as eventTypeId,
22                 callchain_id as callchainId,
23                 (startNS / (${Math.floor((args.endNS - args.startNS) / args.width)})) AS px
24          from (SELECT sp.callchain_id,
25                       (sp.timestamp_trace - ${args.recordStartNS}) / 10000000 * 10000000 startNS,
26                       sum(event_count)                                                   event_count,
27                       count(event_count)                                                 sample_count,
28                       event_type_id
29                from perf_sample sp
30                where sp.thread_id in (select thread_id
31                                       from perf_thread
32                                       where perf_thread.process_id = ${args.pid})
33                  and sp.thread_id != 0 ${args.drawType >= 0 ? 'and event_type_id =' + args.drawType : ''}
34                group by startNS)
35          where startNS + 10000000 >= ${Math.floor(args.startNS)}
36            and startNS <= ${Math.floor(args.endNS)}
37          group by px;`;
38};
39export const chartHiperfProcessDataProtoSql = (args: Args): string => {
40  return `SELECT (sp.timestamp_trace - ${args.recordStartNS})          startNS,
41                 event_count as eventCount,
42                 1 as sampleCount,
43                 event_type_id as eventTypeId,
44                 sp.callchain_id as callchainId,
45                 (sp.timestamp_trace - ${args.recordStartNS}) / (${Math.floor(
46    (args.endNS - args.startNS) / args.width
47  )}) AS px
48          from perf_sample sp
49          where sp.thread_id in (select thread_id
50                                 from perf_thread
51                                 where perf_thread.process_id = ${args.pid})
52            and sp.thread_id != 0 ${args.drawType >= 0 ? 'and event_type_id =' + args.drawType : ''}
53            and startNS >= ${Math.floor(args.startNS)}
54            and startNS <= ${Math.floor(args.endNS)}
55          group by px;`;
56};
57
58export function hiperfProcessDataReceiver(data: unknown, proc: Function): void {
59  let sql: string;
60  // @ts-ignore
61  if (data.params.scale > 30_000_000) {
62    // @ts-ignore
63    sql = chartHiperfProcessData10MSProtoSql(data.params);
64  } else {
65    // @ts-ignore
66    sql = chartHiperfProcessDataProtoSql(data.params);
67  }
68  let res = proc(sql);
69  // @ts-ignore
70  arrayBufferHandler(data, res, data.params.trafic !== TraficEnum.SharedArrayBuffer);
71}
72
73function arrayBufferHandler(data: unknown, res: unknown[], transfer: boolean): void {
74  // @ts-ignore
75  let maxCpuCount = data.params.maxCpuCount;
76  // @ts-ignore
77  let intervalPerf = data.params.intervalPerf;
78  // @ts-ignore
79  let usage = data.params.drawType === -2;
80  let perfProcess = new PerfProcess(data, transfer, res.length);
81  let maxEventCount = Math.max(
82    ...res.map((it) => {
83      // @ts-ignore
84      data.params.trafic === TraficEnum.ProtoBuffer && (it = it.hiperfData);
85      // @ts-ignore
86      return it.eventCount;
87    })
88  );
89  res.forEach((it, i) => {
90    // @ts-ignore
91    data.params.trafic === TraficEnum.ProtoBuffer && (it = it.hiperfData);
92    // @ts-ignore
93    perfProcess.startNS[i] = it.startNS || it.startNs;
94    // @ts-ignore
95    perfProcess.eventCount[i] = it.eventCount;
96    // @ts-ignore
97    perfProcess.sampleCount[i] = it.sampleCount;
98    // @ts-ignore
99    perfProcess.eventTypeId[i] = it.eventTypeId;
100    // @ts-ignore
101    perfProcess.callChainId[i] = it.callchainId;
102    if (usage) {
103      if (maxCpuCount === -1) {
104        // @ts-ignore
105        perfProcess.height[i] = Math.floor((it.sampleCount / (10 / intervalPerf)) * 40);
106      } else {
107        // @ts-ignore
108        perfProcess.height[i] = Math.floor((it.sampleCount / (10 / intervalPerf) / maxCpuCount) * 40);
109      }
110    } else {
111      // @ts-ignore
112      perfProcess.height[i] = Math.floor((it.eventCount / maxEventCount) * 40);
113    }
114  });
115  postPerfProcessMessage(data, transfer, perfProcess, res.length);
116}
117function postPerfProcessMessage(data: unknown, transfer: boolean, perfProcess: PerfProcess, len: number): void {
118  (self as unknown as Worker).postMessage(
119    {
120      // @ts-ignore
121      id: data.id,
122      // @ts-ignore
123      action: data.action,
124      results: transfer
125        ? {
126            startNS: perfProcess.startNS.buffer,
127            eventCount: perfProcess.eventCount.buffer,
128            sampleCount: perfProcess.sampleCount.buffer,
129            eventTypeId: perfProcess.eventTypeId.buffer,
130            callChainId: perfProcess.callChainId.buffer,
131            height: perfProcess.height.buffer,
132          }
133        : {},
134      len: len,
135      transfer: transfer,
136    },
137    transfer
138      ? [
139          perfProcess.startNS.buffer,
140          perfProcess.eventCount.buffer,
141          perfProcess.sampleCount.buffer,
142          perfProcess.eventTypeId.buffer,
143          perfProcess.callChainId.buffer,
144          perfProcess.height.buffer,
145        ]
146      : []
147  );
148}
149class PerfProcess {
150  startNS: Float64Array;
151  eventCount: Int32Array;
152  sampleCount: Int32Array;
153  eventTypeId: Int32Array;
154  callChainId: Int32Array;
155  height: Int32Array;
156  constructor(data: unknown, transfer: boolean, len: number) {
157    // @ts-ignore
158    this.startNS = new Float64Array(transfer ? len : data.params.sharedArrayBuffers.startNS);
159    // @ts-ignore
160    this.eventCount = new Int32Array(transfer ? len : data.params.sharedArrayBuffers.eventCount);
161    // @ts-ignore
162    this.sampleCount = new Int32Array(transfer ? len : data.params.sharedArrayBuffers.sampleCount);
163    // @ts-ignore
164    this.eventTypeId = new Int32Array(transfer ? len : data.params.sharedArrayBuffers.eventTypeId);
165    // @ts-ignore
166    this.callChainId = new Int32Array(transfer ? len : data.params.sharedArrayBuffers.callChainId);
167    // @ts-ignore
168    this.height = new Int32Array(transfer ? len : data.params.sharedArrayBuffers.height);
169  }
170}
171