• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3  * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice, this list of
9  *    conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12  *    of conditions and the following disclaimer in the documentation and/or other materials
13  *    provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16  *    to endorse or promote products derived from this software without specific prior written
17  *    permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include "perf_pmu_pri.h"
33 
34 #define US_PER_SECOND               1000000
35 #define HRTIMER_DEFAULT_PERIOD_US   1000
36 
37 STATIC SwPmu g_perfTimed;
38 
OsPerfTimedPeriodValid(UINT32 period)39 STATIC BOOL OsPerfTimedPeriodValid(UINT32 period)
40 {
41     return period >= TIMER_PERIOD_LOWER_BOUND_US;
42 }
43 
OsPerfTimedStart(VOID)44 STATIC UINT32 OsPerfTimedStart(VOID)
45 {
46     UINT32 i;
47     UINT32 cpuid = ArchCurrCpuid();
48     PerfEvent *events = &g_perfTimed.pmu.events;
49     UINT32 eventNum = events->nr;
50 
51     for (i = 0; i < eventNum; i++) {
52         Event *event = &(events->per[i]);
53         event->count[cpuid] = 0;
54     }
55 
56     if (cpuid != 0) { /* only need start on one core */
57         return LOS_OK;
58     }
59 
60     if (hrtimer_start(&g_perfTimed.hrtimer, g_perfTimed.time, HRTIMER_MODE_REL) != 0) {
61         PRINT_ERR("Hrtimer start failed\n");
62         return LOS_NOK;
63     }
64 
65     if (hrtimer_forward(&g_perfTimed.hrtimer, g_perfTimed.cfgTime) == 0) {
66         PRINT_ERR("Hrtimer forward failed\n");
67         return LOS_NOK;
68     }
69 
70     g_perfTimed.time = g_perfTimed.cfgTime;
71     return LOS_OK;
72 }
73 
OsPerfTimedConfig(VOID)74 STATIC UINT32 OsPerfTimedConfig(VOID)
75 {
76     UINT32 i;
77     PerfEvent *events = &g_perfTimed.pmu.events;
78     UINT32 eventNum = events->nr;
79 
80     for (i = 0; i < eventNum; i++) {
81         Event *event = &(events->per[i]);
82         UINT32 period = event->period;
83         if (event->eventId == PERF_COUNT_CPU_CLOCK) {
84             if (!OsPerfTimedPeriodValid(period)) {
85                 period = TIMER_PERIOD_LOWER_BOUND_US;
86                 PRINT_ERR("config period invalid, should be >= 100, use default period:%u us\n", period);
87             }
88 
89             g_perfTimed.cfgTime = (union ktime) {
90                 .tv.sec  = period / US_PER_SECOND,
91                 .tv.usec = period % US_PER_SECOND
92             };
93             PRINT_INFO("hrtimer config period - sec:%d, usec:%d\n", g_perfTimed.cfgTime.tv.sec,
94                 g_perfTimed.cfgTime.tv.usec);
95             return LOS_OK;
96         }
97     }
98     return LOS_NOK;
99 }
100 
OsPerfTimedStop(VOID)101 STATIC UINT32 OsPerfTimedStop(VOID)
102 {
103     UINT32 ret;
104 
105     if (ArchCurrCpuid() != 0) { /* only need stop on one core */
106         return LOS_OK;
107     }
108 
109     ret = hrtimer_cancel(&g_perfTimed.hrtimer);
110     if (ret != 1) {
111         PRINT_ERR("Hrtimer stop failed!, 0x%x\n", ret);
112         return LOS_NOK;
113     }
114     return LOS_OK;
115 }
116 
OsPerfTimedHandle(VOID)117 STATIC VOID OsPerfTimedHandle(VOID)
118 {
119     UINT32 index;
120     PerfRegs regs;
121 
122     PerfEvent *events = &g_perfTimed.pmu.events;
123     UINT32 eventNum = events->nr;
124 
125     (VOID)memset_s(&regs, sizeof(PerfRegs), 0, sizeof(PerfRegs));
126     OsPerfFetchIrqRegs(&regs);
127 
128     for (index = 0; index < eventNum; index++) {
129         Event *event = &(events->per[index]);
130         OsPerfUpdateEventCount(event, 1); /* eventCount += 1 every once */
131         OsPerfHandleOverFlow(event, &regs);
132     }
133 }
134 
OsPerfHrtimer(struct hrtimer * hrtimer)135 STATIC enum hrtimer_restart OsPerfHrtimer(struct hrtimer *hrtimer)
136 {
137     SMP_CALL_PERF_FUNC(OsPerfTimedHandle); /* send to all cpu to collect data */
138     return HRTIMER_RESTART;
139 }
140 
OsPerfGetEventName(Event * event)141 STATIC CHAR *OsPerfGetEventName(Event *event)
142 {
143     if (event->eventId == PERF_COUNT_CPU_CLOCK) {
144         return "timed";
145     } else {
146         return "unknown";
147     }
148 }
149 
OsTimedPmuInit(VOID)150 UINT32 OsTimedPmuInit(VOID)
151 {
152     UINT32 ret;
153 
154     g_perfTimed.time = (union ktime) {
155         .tv.sec = 0,
156         .tv.usec = HRTIMER_DEFAULT_PERIOD_US,
157     };
158 
159     hrtimer_init(&g_perfTimed.hrtimer, 1, HRTIMER_MODE_REL);
160 
161     ret = hrtimer_create(&g_perfTimed.hrtimer, g_perfTimed.time, OsPerfHrtimer);
162     if (ret != LOS_OK) {
163         return ret;
164     }
165 
166     g_perfTimed.pmu = (Pmu) {
167         .type    = PERF_EVENT_TYPE_TIMED,
168         .config  = OsPerfTimedConfig,
169         .start   = OsPerfTimedStart,
170         .stop    = OsPerfTimedStop,
171         .getName = OsPerfGetEventName,
172     };
173 
174     (VOID)memset_s(&g_perfTimed.pmu.events, sizeof(PerfEvent), 0, sizeof(PerfEvent));
175     ret = OsPerfPmuRegister(&g_perfTimed.pmu);
176     return ret;
177 }
178