1 /*
2 * Copyright (c) 2025 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
16 #include "util/time_format.h"
17 #include <securec.h>
18 #include "dfx/log/ffrt_log_api.h"
19
20 namespace {
21 #if defined(__aarch64__)
22 const uint64_t tsc_base = ffrt::Arm64CntCt();
23 const std::chrono::steady_clock::time_point steady_base = std::chrono::steady_clock::now();
24 const uint64_t freq = ffrt::Arm64CntFrq();
25 #endif
26 }
27 namespace ffrt {
ConvertTscToSteadyClockCount(uint64_t cntCt)28 uint64_t ConvertTscToSteadyClockCount(uint64_t cntCt)
29 {
30 #if defined(__aarch64__)
31 const uint64_t delta_tsc = cntCt - tsc_base;
32 constexpr int ratio = 1000 * 1000;
33
34 const uint64_t delta_micro = (delta_tsc * ratio) / freq;
35
36 return static_cast<uint64_t>(std::chrono::time_point_cast<std::chrono::microseconds>(
37 steady_base + std::chrono::microseconds(delta_micro)).time_since_epoch().count());
38 #else
39 return cntCt;
40 #endif
41 }
42
ConvertCntvctToUs(uint64_t cntCt)43 uint64_t ConvertCntvctToUs(uint64_t cntCt)
44 {
45 // 将获取到的CPU cycle数转成微秒数
46 #if defined(__aarch64__)
47 uint64_t freq = Arm64CntFrq();
48 constexpr int ratio = 1000 * 1000;
49
50 return static_cast<uint64_t>((cntCt * ratio) / freq);
51 #else
52 return cntCt;
53 #endif
54 }
55
ConvertUsToCntvct(uint64_t time)56 uint64_t ConvertUsToCntvct(uint64_t time)
57 {
58 // 将微秒数转成CPU cycle数
59 #if defined(__aarch64__)
60 uint64_t freq = Arm64CntFrq();
61 constexpr int ratio = 1000 * 1000;
62
63 return static_cast<uint64_t>((time * freq) / ratio);
64 #else
65 return time;
66 #endif
67 }
68
TimeStampCntvct()69 uint64_t TimeStampCntvct()
70 {
71 // 在非arm环境下获取std的时间戳,单位微秒
72 return static_cast<uint64_t>(std::chrono::time_point_cast<std::chrono::microseconds>(
73 std::chrono::steady_clock::now()).time_since_epoch().count());
74 }
75
FormatDateToString(uint64_t timeStamp)76 std::string FormatDateToString(uint64_t timeStamp)
77 {
78 #if defined(__aarch64__)
79 return FormatDateString4CntCt(timeStamp, MICROSECOND);
80 #else
81 return FormatDateString4SteadyClock(timeStamp, MICROSECOND);
82 #endif
83 }
84
Arm64CntFrq(void)85 uint64_t Arm64CntFrq(void)
86 {
87 uint64_t freq = 1;
88 #if defined(__aarch64__)
89 asm volatile("mrs %0, cntfrq_el0" : "=r" (freq));
90 #endif
91 return freq;
92 }
93
Arm64CntCt(void)94 uint64_t Arm64CntCt(void)
95 {
96 uint64_t tsc = 1;
97 #if defined(__aarch64__)
98 asm volatile("mrs %0, cntvct_el0" : "=r" (tsc));
99 #endif
100 return tsc;
101 }
102
FormatDateString4SystemClock(const std::chrono::system_clock::time_point & timePoint,TimeUnitT timeUnit)103 std::string FormatDateString4SystemClock(const std::chrono::system_clock::time_point& timePoint,
104 TimeUnitT timeUnit)
105 {
106 constexpr int maxMsLength = 3;
107 constexpr int msPerSecond = 1000;
108 constexpr int datetimeStringLength = 80;
109 constexpr int maxUsLength = 6;
110 constexpr int usPerSecond = 1000 * 1000;
111
112 std::string remainder;
113 if (timeUnit == MICROSECOND) {
114 auto tp = std::chrono::time_point_cast<std::chrono::microseconds>(timePoint);
115 auto us = tp.time_since_epoch().count() % usPerSecond;
116 remainder = std::to_string(us);
117 if (remainder.length() < maxUsLength) {
118 remainder = std::string(maxUsLength - remainder.length(), '0') + remainder;
119 }
120 } else {
121 auto tp = std::chrono::time_point_cast<std::chrono::milliseconds>(timePoint);
122 auto ms = tp.time_since_epoch().count() % msPerSecond;
123 remainder = std::to_string(ms);
124 if (remainder.length() < maxMsLength) {
125 remainder = std::string(maxMsLength - remainder.length(), '0') + remainder;
126 }
127 }
128 auto tt = std::chrono::system_clock::to_time_t(timePoint);
129 struct tm curTime;
130 if (memset_s(&curTime, sizeof(curTime), 0, sizeof(curTime)) != EOK) {
131 FFRT_LOGE("Fail to memset");
132 return "";
133 }
134 localtime_r(&tt, &curTime);
135 char sysTime[datetimeStringLength];
136 std::strftime(sysTime, sizeof(char) * datetimeStringLength, "%Y-%m-%d %H:%M:%S.", &curTime);
137 return std::string(sysTime) + remainder;
138 }
139
FormatDateString4SteadyClock(uint64_t steadyClockTimeStamp,TimeUnitT timeUnit)140 std::string FormatDateString4SteadyClock(uint64_t steadyClockTimeStamp, TimeUnitT timeUnit)
141 {
142 auto referenceTimeStamp = std::chrono::duration_cast<std::chrono::microseconds>(
143 std::chrono::steady_clock::now().time_since_epoch()).count();
144 auto referenceTp = std::chrono::system_clock::now();
145
146 std::chrono::microseconds us(static_cast<int64_t>(steadyClockTimeStamp - referenceTimeStamp));
147 return FormatDateString4SystemClock(referenceTp + us, timeUnit);
148 }
149
FormatDateString4CntCt(uint64_t cntCtTimeStamp,TimeUnitT timeUnit)150 std::string FormatDateString4CntCt(uint64_t cntCtTimeStamp, TimeUnitT timeUnit)
151 {
152 constexpr int ratio = 1000 * 1000;
153
154 int64_t referenceFreq = static_cast<int64_t>(Arm64CntFrq());
155 if (referenceFreq == 0) {
156 return "";
157 }
158 uint64_t referenceCntCt = Arm64CntCt();
159 auto globalTp = std::chrono::system_clock::now();
160 std::chrono::microseconds us(static_cast<int64_t>(cntCtTimeStamp - referenceCntCt) * ratio / referenceFreq);
161 return FormatDateString4SystemClock(globalTp + us, timeUnit);
162 }
163 } // namespace ffrt
164