@@ -75,6 +75,7 @@ struct UnrefPtr<std::unique_ptr<Arg, D>> : std::true_type
75
75
template <typename Arg>
76
76
struct UnrefPtr <Arg*> : std::true_type
77
77
{ using type = Arg; };
78
+
78
79
}; // namespace fmtlogdetail
79
80
80
81
template <int __ = 0 >
@@ -101,8 +102,8 @@ class fmtlogT
101
102
// Set the file for logging
102
103
static void setLogFile (const char * filename, bool truncate = false );
103
104
104
- // Set an existing FILE* for logging, if manageFp is false fmtlog will not buffer log internally and will not close
105
- // the FILE*
105
+ // Set an existing FILE* for logging, if manageFp is false fmtlog will not buffer log internally
106
+ // and will not close the FILE*
106
107
static void setLogFile (FILE* fp, bool manageFp = false );
107
108
108
109
// Collect log msgs from all threads and write to log file
@@ -130,7 +131,8 @@ class fmtlogT
130
131
// bodyPos: log body index in the msg
131
132
// logFilePos: log file position of this msg
132
133
typedef void (*LogCBFn)(int64_t ns, LogLevel level, fmt::string_view location, size_t basePos,
133
- fmt::string_view threadName, fmt::string_view msg, size_t bodyPos, size_t logFilePos);
134
+ fmt::string_view threadName, fmt::string_view msg, size_t bodyPos,
135
+ size_t logFilePos);
134
136
135
137
// Set a callback function for all log msgs with a mininum log level
136
138
static void setLogCB (LogCBFn cb, LogLevel minCBLogLevel);
@@ -158,54 +160,30 @@ class fmtlogT
158
160
// Stop the polling thread
159
161
static void stopPollingThread ();
160
162
161
- private:
162
- fmtlogT () { init (); }
163
-
164
- void init () {
165
- if (!inited) {
166
- inited = true ;
167
- tscns.init ();
168
- currentLogLevel = INF;
169
- }
170
- }
171
-
172
- template <int >
173
- friend class fmtlogDetailT ;
174
- template <int >
175
- friend struct fmtlogWrapper ;
176
- template <typename S, typename ... Args>
177
- friend void test (const S& format, Args&&...);
178
-
179
- using Context = fmt::format_context;
180
- using MemoryBuffer = fmt::basic_memory_buffer<char , 10000 >;
181
- typedef const char * (*FormatToFn)(fmt::string_view format, const char * data, MemoryBuffer& out, int & argIdx,
182
- std::vector<fmt::basic_format_arg<Context>>& args);
183
-
184
- static void registerLogInfo (uint32_t & logId, FormatToFn fn, const char * location, LogLevel level,
185
- fmt::string_view fmtString);
186
-
187
163
// https://github.com/MengRao/SPSC_Queue
188
- template <uint32_t Bytes = 1 << 20 >
189
164
class SPSCVarQueueOPT
190
165
{
191
166
public:
192
167
struct MsgHeader
193
168
{
169
+ inline void push (uint32_t sz) { *(volatile uint32_t *)&size = sz + sizeof (MsgHeader); }
170
+
194
171
uint32_t size;
195
172
uint32_t logId;
196
173
};
197
- static constexpr uint32_t BLK_CNT = Bytes / sizeof (MsgHeader);
174
+ static constexpr uint32_t BLK_CNT = (1 << 20 ) / sizeof (MsgHeader);
175
+
176
+ MsgHeader* allocMsg (uint32_t size);
198
177
199
- MsgHeader* alloc (uint32_t size_ ) {
200
- size = size_ + sizeof (MsgHeader);
178
+ MsgHeader* alloc (uint32_t size ) {
179
+ size += sizeof (MsgHeader);
201
180
uint32_t blk_sz = (size + sizeof (MsgHeader) - 1 ) / sizeof (MsgHeader);
202
181
if (blk_sz >= free_write_cnt) {
203
182
uint32_t read_idx_cache = *(volatile uint32_t *)&read_idx;
204
183
if (read_idx_cache <= write_idx) {
205
184
free_write_cnt = BLK_CNT - write_idx;
206
185
if (blk_sz >= free_write_cnt && read_idx_cache != 0 ) { // wrap around
207
186
blk[0 ].size = 0 ;
208
- std::atomic_thread_fence (std::memory_order_release);
209
187
blk[write_idx].size = 1 ;
210
188
write_idx = 0 ;
211
189
free_write_cnt = read_idx_cache;
@@ -218,28 +196,14 @@ class fmtlogT
218
196
return nullptr ;
219
197
}
220
198
}
221
- return &blk[write_idx];
222
- }
223
-
224
- void push () {
225
- uint32_t blk_sz = (size + sizeof (MsgHeader) - 1 ) / sizeof (MsgHeader);
226
- blk[write_idx + blk_sz].size = 0 ;
227
- std::atomic_thread_fence (std::memory_order_release);
228
- blk[write_idx].size = size;
199
+ MsgHeader* ret = &blk[write_idx];
229
200
write_idx += blk_sz;
230
201
free_write_cnt -= blk_sz;
202
+ blk[write_idx].size = 0 ;
203
+ return ret;
231
204
}
232
205
233
- template <typename Writer>
234
- bool tryPush (uint32_t size, Writer writer) {
235
- MsgHeader* header = alloc (size);
236
- if (!header) return false ;
237
- writer (header);
238
- push ();
239
- return true ;
240
- }
241
-
242
- const MsgHeader* front () {
206
+ inline const MsgHeader* front () {
243
207
uint32_t size = blk[read_idx].size ;
244
208
if (size == 1 ) { // wrap around
245
209
read_idx = 0 ;
@@ -249,33 +213,22 @@ class fmtlogT
249
213
return &blk[read_idx];
250
214
}
251
215
252
- void pop () {
216
+ inline void pop () {
253
217
uint32_t blk_sz = (blk[read_idx].size + sizeof (MsgHeader) - 1 ) / sizeof (MsgHeader);
254
218
*(volatile uint32_t *)&read_idx = read_idx + blk_sz;
255
219
}
256
220
257
- template <typename Reader>
258
- bool tryPop (Reader reader) {
259
- MsgHeader* header = front ();
260
- if (!header) return false ;
261
- reader (header);
262
- pop ();
263
- return true ;
264
- }
265
-
266
221
private:
267
222
alignas (64 ) MsgHeader blk[BLK_CNT] = {};
268
-
269
- alignas (128 ) uint32_t write_idx = 0 ;
223
+ uint32_t write_idx = 0 ;
270
224
uint32_t free_write_cnt = BLK_CNT;
271
- uint32_t size;
272
225
273
226
alignas (128 ) uint32_t read_idx = 0 ;
274
227
};
275
228
276
229
struct ThreadBuffer
277
230
{
278
- SPSCVarQueueOPT<> varq;
231
+ SPSCVarQueueOPT varq;
279
232
bool shouldDeallocate = false ;
280
233
char name[32 ];
281
234
size_t nameSize;
@@ -294,7 +247,8 @@ class fmtlogT
294
247
}
295
248
else {
296
249
#ifdef _WIN32
297
- return calibrate (1000000 * 100 ); // wait more time as Windows' system time is in 100ns precision
250
+ return calibrate (1000000 *
251
+ 100 ); // wait more time as Windows' system time is in 100ns precision
298
252
#else
299
253
return calibrate (1000000 * 10 ); //
300
254
#endif
@@ -355,18 +309,33 @@ class fmtlogT
355
309
356
310
void adjustOffset () { ns_offset = base_ns - (int64_t )(base_tsc * tsc_ghz_inv); }
357
311
358
- alignas (64 ) double tsc_ghz_inv; // make sure tsc_ghz_inv and ns_offset are on the same cache line
312
+ alignas (64 ) double tsc_ghz_inv;
359
313
int64_t ns_offset;
360
314
int64_t base_tsc;
361
315
int64_t base_ns;
362
316
};
363
317
364
- bool inited = false ;
318
+ void init () {
319
+ tscns.init ();
320
+ currentLogLevel = INF;
321
+ }
322
+
323
+ using Context = fmt::format_context;
324
+ using MemoryBuffer = fmt::basic_memory_buffer<char , 10000 >;
325
+ typedef const char * (*FormatToFn)(fmt::string_view format, const char * data, MemoryBuffer& out,
326
+ int & argIdx, std::vector<fmt::basic_format_arg<Context>>& args);
327
+
328
+ static void registerLogInfo (uint32_t & logId, FormatToFn fn, const char * location, LogLevel level,
329
+ fmt::string_view fmtString);
330
+
331
+ static void vformat_to (MemoryBuffer& out, fmt::string_view fmt, fmt::format_args args);
332
+
333
+ static size_t formatted_size (fmt::string_view fmt, fmt::format_args args);
334
+
335
+ static void vformat_to (char * out, fmt::string_view fmt, fmt::format_args args);
365
336
366
- public:
367
337
TSCNS tscns;
368
338
369
- private:
370
339
volatile LogLevel currentLogLevel;
371
340
static FAST_THREAD_LOCAL ThreadBuffer* threadBuffer;
372
341
@@ -550,8 +519,8 @@ class fmtlogT
550
519
}
551
520
552
521
template <typename ... Args>
553
- static const char * formatTo (fmt::string_view format, const char * data, MemoryBuffer& out, int & argIdx,
554
- std::vector<fmt::basic_format_arg<Context>>& args) {
522
+ static const char * formatTo (fmt::string_view format, const char * data, MemoryBuffer& out,
523
+ int & argIdx, std::vector<fmt::basic_format_arg<Context>>& args) {
555
524
constexpr size_t num_args = sizeof ...(Args);
556
525
constexpr size_t num_dtors = fmt::detail::count<needCallDtor<Args>()...>();
557
526
const char * dtor_args[std::max (num_dtors, (size_t )1 )];
@@ -564,7 +533,7 @@ class fmtlogT
564
533
else {
565
534
ret = decodeArgs<true , 0 , 0 , Args...>(data, args.data () + argIdx, dtor_args);
566
535
}
567
- fmt::detail:: vformat_to (out, format, fmt::basic_format_args (args.data () + argIdx, num_args));
536
+ vformat_to (out, format, fmt::basic_format_args (args.data () + argIdx, num_args));
568
537
destructArgs<0 , Args...>(dtor_args);
569
538
570
539
return ret;
@@ -642,17 +611,17 @@ class fmtlogT
642
611
}
643
612
constexpr size_t num_cstring = fmt::detail::count<isCstring<Args>()...>();
644
613
size_t cstringSizes[std::max (num_cstring, (size_t )1 )];
645
- size_t allocSize = getArgSizes<0 >(cstringSizes, args...) + 8 ;
614
+ size_t alloc_size = 8 + getArgSizes<0 >(cstringSizes, args...);
646
615
if (threadBuffer == nullptr ) preallocate ();
647
616
do {
648
- if ( threadBuffer->varq .tryPush (allocSize, [&]( typename SPSCVarQueueOPT<>::MsgHeader* header) {
649
- header-> logId = logId ;
650
- char * writePos = ( char *)(header + 1 ) ;
651
- *( int64_t *)writePos = tsc ;
652
- writePos += 8 ;
653
- encodeArgs< 0 >(cstringSizes, writePos, std::forward<Args>(args)...) ;
654
- }))
655
- return ;
617
+ auto header = threadBuffer->varq .allocMsg (alloc_size);
618
+ if (! header) continue ;
619
+ header-> logId = logId ;
620
+ char * out = ( char *)(header + 1 ) ;
621
+ *( int64_t *)out = tsc ;
622
+ out += 8 ;
623
+ encodeArgs< 0 >(cstringSizes, out, std::forward<Args>(args)...);
624
+ header-> push (alloc_size) ;
656
625
} while (FMTLOG_BLOCK);
657
626
}
658
627
@@ -663,20 +632,21 @@ class fmtlogT
663
632
fmt::detail::check_format_string<Args...>(format);
664
633
}
665
634
fmt::string_view sv (format);
666
- size_t formatted_size = fmt::formatted_size (fmt::runtime (sv), args...);
667
- size_t allocSize = formatted_size + 8 + 8 ;
635
+ auto && fmt_args = fmt::make_format_args (args...);
636
+ size_t fmt_size = formatted_size (sv, fmt_args);
637
+ size_t alloc_size = 8 + 8 + fmt_size;
668
638
if (threadBuffer == nullptr ) preallocate ();
669
639
do {
670
- if ( threadBuffer->varq .tryPush (allocSize, [&]( typename SPSCVarQueueOPT<>::MsgHeader* header) {
671
- header-> logId = ( uint32_t )level ;
672
- char * writePos = (char *)(header + 1 ) ;
673
- *( int64_t *)writePos = tscns. rdtsc ( );
674
- writePos += 8 ;
675
- *( const char **)writePos = location ;
676
- writePos += 8 ;
677
- fmt::format_to (writePos, fmt::runtime (sv), args...) ;
678
- }))
679
- return ;
640
+ auto header = threadBuffer->varq .allocMsg (alloc_size);
641
+ if (!header) continue ;
642
+ header-> logId = (uint32_t )level ;
643
+ char * out = ( char *)(header + 1 );
644
+ *( int64_t *)out = tscns. rdtsc () ;
645
+ out += 8 ;
646
+ *( const char **)out = location ;
647
+ out += 8 ;
648
+ vformat_to (out, sv, fmt_args);
649
+ header-> push (alloc_size) ;
680
650
} while (FMTLOG_BLOCK);
681
651
}
682
652
};
0 commit comments