Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
S
spdlog
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
spdlog
Commits
df898267
Commit
df898267
authored
Dec 03, 2014
by
gabime
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'cppformat' of
https://github.com/gabime/spdlog
into cppformat
parents
d89628bb
98e4eb98
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
388 additions
and
57 deletions
+388
-57
include/spdlog/async_logger.h
include/spdlog/async_logger.h
+3
-3
include/spdlog/details/async_log_helper.h
include/spdlog/details/async_log_helper.h
+295
-0
include/spdlog/details/async_logger_impl.h
include/spdlog/details/async_logger_impl.h
+12
-13
include/spdlog/details/file_helper.h
include/spdlog/details/file_helper.h
+1
-1
include/spdlog/details/format.cc
include/spdlog/details/format.cc
+0
-1
include/spdlog/details/format.h
include/spdlog/details/format.h
+2
-2
include/spdlog/details/log_msg.h
include/spdlog/details/log_msg.h
+6
-2
include/spdlog/details/mpcs_q.h
include/spdlog/details/mpcs_q.h
+58
-24
include/spdlog/details/pattern_formatter_impl.h
include/spdlog/details/pattern_formatter_impl.h
+11
-11
No files found.
include/spdlog/async_logger.h
View file @
df898267
...
@@ -37,9 +37,9 @@
...
@@ -37,9 +37,9 @@
namespace
spdlog
namespace
spdlog
{
{
namespace
sink
s
namespace
detail
s
{
{
class
async_
sink
;
class
async_
log_helper
;
}
}
class
async_logger
:
public
logger
class
async_logger
:
public
logger
...
@@ -59,7 +59,7 @@ protected:
...
@@ -59,7 +59,7 @@ protected:
private:
private:
log_clock
::
duration
_shutdown_duration
;
log_clock
::
duration
_shutdown_duration
;
std
::
unique_ptr
<
sinks
::
async_sink
>
_as
;
std
::
unique_ptr
<
details
::
async_log_helper
>
_async_log_helper
;
};
};
}
}
...
...
include/spdlog/
sinks/async_sink
.h
→
include/spdlog/
details/async_log_helper
.h
View file @
df898267
...
@@ -22,7 +22,7 @@
...
@@ -22,7 +22,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
/*************************************************************************/
// async
sink
:
// async
log helper
:
// Process logs asynchronously using a back thread.
// Process logs asynchronously using a back thread.
//
//
// If the internal queue of log messages reaches its max size,
// If the internal queue of log messages reaches its max size,
...
@@ -30,36 +30,71 @@
...
@@ -30,36 +30,71 @@
//
//
// If the back thread throws during logging, a spdlog::spdlog_ex exception
// If the back thread throws during logging, a spdlog::spdlog_ex exception
// will be thrown in client's thread when tries to log the next message
// will be thrown in client's thread when tries to log the next message
#pragma once
#pragma once
#include <thread>
#include <thread>
#include <chrono>
#include <chrono>
#include <atomic>
#include <atomic>
#include ".
/base_
sink.h"
#include ".
./sinks/
sink.h"
#include "../logger.h"
#include "../logger.h"
#include "../details/blocking_queue.h"
#include "../details/mpcs_q.h"
#include "../details/null_mutex.h"
#include "../details/log_msg.h"
#include "../details/log_msg.h"
#include "../details/format.h"
#include "../details/format.h"
namespace
spdlog
namespace
spdlog
{
{
namespace
sink
s
namespace
detail
s
{
{
class
async_log_helper
class
async_sink
:
public
base_sink
<
details
::
null_mutex
>
//single worker thread so null_mutex
{
{
struct
async_msg
{
std
::
string
logger_name
;
level
::
level_enum
level
;
log_clock
::
time_point
time
;
std
::
tm
tm_time
;
std
::
string
raw_msg_str
;
async_msg
()
=
default
;
async_msg
(
const
details
::
log_msg
&
m
)
:
logger_name
(
m
.
logger_name
),
level
(
m
.
level
),
time
(
m
.
time
),
tm_time
(
m
.
tm_time
),
raw_msg_str
(
m
.
raw
.
data
(),
m
.
raw
.
size
())
{
}
log_msg
to_log_msg
()
{
log_msg
msg
;
msg
.
logger_name
=
logger_name
;
msg
.
level
=
level
;
msg
.
time
=
time
;
msg
.
tm_time
=
tm_time
;
msg
.
raw
<<
raw_msg_str
;
return
msg
;
}
};
public:
public:
using
q_type
=
details
::
blocking_queue
<
details
::
log_msg
>
;
using
q_type
=
details
::
mpsc_q
<
std
::
unique_ptr
<
async_msg
>
>
;
using
clock
=
std
::
chrono
::
monotonic_clock
;
explicit
async_sink
(
const
q_type
::
size_type
max_queue_size
);
explicit
async_log_helper
(
size_t
max_queue_size
);
void
log
(
const
details
::
log_msg
&
msg
);
//Stop logging and join the back thread
//Stop logging and join the back thread
~
async_
sink
();
~
async_
log_helper
();
void
add_sink
(
sink_ptr
sink
);
void
add_sink
(
sink_ptr
sink
);
void
remove_sink
(
sink_ptr
sink_ptr
);
void
remove_sink
(
sink_ptr
sink_ptr
);
void
set_formatter
(
formatter_ptr
);
void
set_formatter
(
formatter_ptr
);
...
@@ -68,25 +103,33 @@ public:
...
@@ -68,25 +103,33 @@ public:
protected:
void
_sink_it
(
const
details
::
log_msg
&
msg
)
override
;
void
_thread_loop
();
private:
private:
std
::
vector
<
std
::
shared_ptr
<
sink
>>
_sinks
;
std
::
vector
<
std
::
shared_ptr
<
sink
s
::
sink
>>
_sinks
;
std
::
atomic
<
bool
>
_active
;
std
::
atomic
<
bool
>
_active
;
q_type
_q
;
q_type
_q
;
std
::
thread
_
back
_thread
;
std
::
thread
_
worker
_thread
;
std
::
mutex
_mutex
;
std
::
mutex
_mutex
;
//Last exception thrown from the back thread
std
::
shared_ptr
<
spdlog_ex
>
_last_backthread_ex
;
// last exception thrown from the worker thread
std
::
shared_ptr
<
spdlog_ex
>
_last_workerthread_ex
;
// worker thread formatter
formatter_ptr
_formatter
;
formatter_ptr
_formatter
;
//will throw last back thread exception or if backthread no active
// will throw last back thread exception or if worker hread no active
void
_push_sentry
();
void
_push_sentry
();
//Clear all remaining messages(if any), stop the _back_thread and join it
// worker thread loop
void
_thread_loop
();
// guess how much to sleep if queue is empty/full using last succesful op time as hint
static
void
_sleep_or_yield
(
const
clock
::
time_point
&
last_op_time
);
// clear all remaining messages(if any), stop the _worker_thread and join it
void
_join
();
void
_join
();
};
};
...
@@ -96,85 +139,103 @@ private:
...
@@ -96,85 +139,103 @@ private:
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// async_sink class implementation
// async_sink class implementation
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
inline
spdlog
::
sinks
::
async_sink
::
async_sink
(
const
q_type
::
size_type
max_queue_size
)
inline
spdlog
::
details
::
async_log_helper
::
async_log_helper
(
size_t
max_queue_size
)
:
_sinks
(),
:
_sinks
(),
_active
(
true
),
_active
(
true
),
_q
(
max_queue_size
),
_q
(
max_queue_size
),
_
back_thread
(
&
async_sink
::
_thread_loop
,
this
)
_
worker_thread
(
&
async_log_helper
::
_thread_loop
,
this
)
{}
{}
inline
spdlog
::
sinks
::
async_sink
::~
async_sink
()
inline
spdlog
::
details
::
async_log_helper
::~
async_log_helper
()
{
{
_join
();
_join
();
}
}
inline
void
spdlog
::
sinks
::
async_sink
::
_sink_it
(
const
details
::
log_msg
&
msg
)
//Try to push and block until succeeded
inline
void
spdlog
::
details
::
async_log_helper
::
log
(
const
details
::
log_msg
&
msg
)
{
{
_push_sentry
();
_push_sentry
();
_q
.
push
(
std
::
move
(
msg
));
//Only if queue is full, enter wait loop
if
(
!
_q
.
push
(
std
::
unique_ptr
<
async_msg
>
(
new
async_msg
(
msg
))))
{
auto
last_op_time
=
clock
::
now
();
do
{
_sleep_or_yield
(
last_op_time
);
}
while
(
!
_q
.
push
(
std
::
unique_ptr
<
async_msg
>
(
new
async_msg
(
msg
))));
}
}
}
inline
void
spdlog
::
sinks
::
async_sink
::
_thread_loop
()
inline
void
spdlog
::
details
::
async_log_helper
::
_thread_loop
()
{
{
std
::
chrono
::
seconds
pop_timeout
{
1
};
clock
::
time_point
last_pop
=
clock
::
now
();
while
(
_active
)
while
(
_active
)
{
{
q_type
::
item_type
msg
;
q_type
::
item_type
async_msg
;
if
(
_q
.
pop
(
msg
,
pop_timeout
))
if
(
_q
.
pop
(
async_msg
))
{
{
if
(
!
_active
)
return
;
last_pop
=
clock
::
now
()
;
try
try
{
{
details
::
log_msg
log_msg
=
async_msg
->
to_log_msg
();
_formatter
->
format
(
msg
);
_formatter
->
format
(
log_
msg
);
for
(
auto
&
s
:
_sinks
)
for
(
auto
&
s
:
_sinks
)
s
->
log
(
msg
);
s
->
log
(
log_
msg
);
}
}
catch
(
const
std
::
exception
&
ex
)
catch
(
const
std
::
exception
&
ex
)
{
{
_last_
back
thread_ex
=
std
::
make_shared
<
spdlog_ex
>
(
ex
.
what
());
_last_
worker
thread_ex
=
std
::
make_shared
<
spdlog_ex
>
(
ex
.
what
());
}
}
catch
(...)
catch
(...)
{
{
_last_
back
thread_ex
=
std
::
make_shared
<
spdlog_ex
>
(
"Unknown exception"
);
_last_
worker
thread_ex
=
std
::
make_shared
<
spdlog_ex
>
(
"Unknown exception"
);
}
}
}
// sleep or yield if queue is empty.
else
{
_sleep_or_yield
(
last_pop
);
}
}
}
}
}
}
inline
void
spdlog
::
sinks
::
async_sink
::
add_sink
(
spdlog
::
sink_ptr
s
)
inline
void
spdlog
::
details
::
async_log_helper
::
add_sink
(
spdlog
::
sink_ptr
s
)
{
{
std
::
lock_guard
<
std
::
mutex
>
guard
(
_mutex
);
std
::
lock_guard
<
std
::
mutex
>
guard
(
_mutex
);
_sinks
.
push_back
(
s
);
_sinks
.
push_back
(
s
);
}
}
inline
void
spdlog
::
sinks
::
async_sink
::
remove_sink
(
spdlog
::
sink_ptr
s
)
inline
void
spdlog
::
details
::
async_log_helper
::
remove_sink
(
spdlog
::
sink_ptr
s
)
{
{
std
::
lock_guard
<
std
::
mutex
>
guard
(
_mutex
);
std
::
lock_guard
<
std
::
mutex
>
guard
(
_mutex
);
_sinks
.
erase
(
std
::
remove
(
_sinks
.
begin
(),
_sinks
.
end
(),
s
),
_sinks
.
end
());
_sinks
.
erase
(
std
::
remove
(
_sinks
.
begin
(),
_sinks
.
end
(),
s
),
_sinks
.
end
());
}
}
inline
void
spdlog
::
sinks
::
async_sink
::
set_formatter
(
formatter_ptr
msg_formatter
)
inline
void
spdlog
::
details
::
async_log_helper
::
set_formatter
(
formatter_ptr
msg_formatter
)
{
{
_formatter
=
msg_formatter
;
_formatter
=
msg_formatter
;
}
}
inline
void
spdlog
::
sinks
::
async_sink
::
shutdown
(
const
log_clock
::
duration
&
timeout
)
inline
void
spdlog
::
details
::
async_log_helper
::
shutdown
(
const
log_clock
::
duration
&
timeout
)
{
{
if
(
timeout
>
std
::
chrono
::
milliseconds
::
zero
())
if
(
timeout
>
std
::
chrono
::
milliseconds
::
zero
())
{
{
auto
until
=
log_clock
::
now
()
+
timeout
;
auto
until
=
log_clock
::
now
()
+
timeout
;
while
(
_q
.
size
()
>
0
&&
log_clock
::
now
()
<
until
)
while
(
_q
.
approx_
size
()
>
0
&&
log_clock
::
now
()
<
until
)
{
{
std
::
this_thread
::
sleep_for
(
std
::
chrono
::
milliseconds
(
5
));
std
::
this_thread
::
sleep_for
(
std
::
chrono
::
milliseconds
(
5
));
}
}
...
@@ -182,13 +243,30 @@ inline void spdlog::sinks::async_sink::shutdown(const log_clock::duration& timeo
...
@@ -182,13 +243,30 @@ inline void spdlog::sinks::async_sink::shutdown(const log_clock::duration& timeo
_join
();
_join
();
}
}
#include <iostream>
inline
void
spdlog
::
sinks
::
async_sink
::
_push_sentry
()
// Sleep or yield using the time passed since last message as a hint
inline
void
spdlog
::
details
::
async_log_helper
::
_sleep_or_yield
(
const
clock
::
time_point
&
last_op_time
)
{
using
std
::
chrono
::
milliseconds
;
using
std
::
this_thread
::
sleep_for
;
using
std
::
this_thread
::
yield
;
clock
::
duration
sleep_duration
;
auto
time_since_op
=
clock
::
now
()
-
last_op_time
;
if
(
time_since_op
>
milliseconds
(
1000
))
sleep_for
(
milliseconds
(
500
));
else
if
(
time_since_op
>
milliseconds
(
1
))
sleep_for
(
time_since_op
/
2
);
else
yield
();
}
inline
void
spdlog
::
details
::
async_log_helper
::
_push_sentry
()
{
{
if
(
_last_
back
thread_ex
)
if
(
_last_
worker
thread_ex
)
{
{
auto
ex
=
std
::
move
(
_last_
back
thread_ex
);
auto
ex
=
std
::
move
(
_last_
worker
thread_ex
);
_last_
back
thread_ex
.
reset
();
_last_
worker
thread_ex
.
reset
();
throw
*
ex
;
throw
*
ex
;
}
}
if
(
!
_active
)
if
(
!
_active
)
...
@@ -196,18 +274,22 @@ inline void spdlog::sinks::async_sink::_push_sentry()
...
@@ -196,18 +274,22 @@ inline void spdlog::sinks::async_sink::_push_sentry()
}
}
inline
void
spdlog
::
sinks
::
async_sink
::
_join
()
inline
void
spdlog
::
details
::
async_log_helper
::
_join
()
{
{
_active
=
false
;
_active
=
false
;
if
(
_
back
_thread
.
joinable
())
if
(
_
worker
_thread
.
joinable
())
{
{
try
try
{
{
_
back
_thread
.
join
();
_
worker
_thread
.
join
();
}
}
catch
(
const
std
::
system_error
&
)
//Dont crash if thread not joinable
catch
(
const
std
::
system_error
&
)
//Dont crash if thread not joinable
{}
{
}
}
}
}
}
include/spdlog/details/async_logger_impl.h
View file @
df898267
...
@@ -25,8 +25,7 @@
...
@@ -25,8 +25,7 @@
#pragma once
#pragma once
#include <memory>
#include "./async_log_helper.h"
#include "../sinks/async_sink.h"
//
//
// Async Logger implementation
// Async Logger implementation
...
@@ -38,11 +37,11 @@ template<class It>
...
@@ -38,11 +37,11 @@ template<class It>
inline
spdlog
::
async_logger
::
async_logger
(
const
std
::
string
&
logger_name
,
const
It
&
begin
,
const
It
&
end
,
size_t
queue_size
,
const
log_clock
::
duration
&
shutdown_duration
)
:
inline
spdlog
::
async_logger
::
async_logger
(
const
std
::
string
&
logger_name
,
const
It
&
begin
,
const
It
&
end
,
size_t
queue_size
,
const
log_clock
::
duration
&
shutdown_duration
)
:
logger
(
logger_name
,
begin
,
end
),
logger
(
logger_name
,
begin
,
end
),
_shutdown_duration
(
shutdown_duration
),
_shutdown_duration
(
shutdown_duration
),
_as
(
std
::
unique_ptr
<
sinks
::
async_sink
>
(
new
sinks
::
async_sink
(
queue_size
)
))
_as
ync_log_helper
(
new
details
::
async_log_helper
(
queue_size
))
{
{
_as
->
set_formatter
(
_formatter
);
_as
ync_log_helper
->
set_formatter
(
_formatter
);
for
(
auto
&
s
:
_sinks
)
for
(
auto
&
s
:
_sinks
)
_as
->
add_sink
(
s
);
_as
ync_log_helper
->
add_sink
(
s
);
}
}
inline
spdlog
::
async_logger
::
async_logger
(
const
std
::
string
&
logger_name
,
sinks_init_list
sinks
,
size_t
queue_size
,
const
log_clock
::
duration
&
shutdown_duration
)
:
inline
spdlog
::
async_logger
::
async_logger
(
const
std
::
string
&
logger_name
,
sinks_init_list
sinks
,
size_t
queue_size
,
const
log_clock
::
duration
&
shutdown_duration
)
:
...
@@ -52,21 +51,16 @@ inline spdlog::async_logger::async_logger(const std::string& logger_name, sink_p
...
@@ -52,21 +51,16 @@ inline spdlog::async_logger::async_logger(const std::string& logger_name, sink_p
async_logger
(
logger_name
,
{
single_sink
},
queue_size
,
shutdown_duration
)
{}
async_logger
(
logger_name
,
{
single_sink
},
queue_size
,
shutdown_duration
)
{}
inline
void
spdlog
::
async_logger
::
_log_msg
(
details
::
log_msg
&
msg
)
{
_as
->
log
(
msg
);
}
inline
void
spdlog
::
async_logger
::
_set_formatter
(
spdlog
::
formatter_ptr
msg_formatter
)
inline
void
spdlog
::
async_logger
::
_set_formatter
(
spdlog
::
formatter_ptr
msg_formatter
)
{
{
_formatter
=
msg_formatter
;
_formatter
=
msg_formatter
;
_as
->
set_formatter
(
_formatter
);
_as
ync_log_helper
->
set_formatter
(
_formatter
);
}
}
inline
void
spdlog
::
async_logger
::
_set_pattern
(
const
std
::
string
&
pattern
)
inline
void
spdlog
::
async_logger
::
_set_pattern
(
const
std
::
string
&
pattern
)
{
{
_formatter
=
std
::
make_shared
<
pattern_formatter
>
(
pattern
);
_formatter
=
std
::
make_shared
<
pattern_formatter
>
(
pattern
);
_as
->
set_formatter
(
_formatter
);
_as
ync_log_helper
->
set_formatter
(
_formatter
);
}
}
...
@@ -74,5 +68,10 @@ inline void spdlog::async_logger::_set_pattern(const std::string& pattern)
...
@@ -74,5 +68,10 @@ inline void spdlog::async_logger::_set_pattern(const std::string& pattern)
inline
void
spdlog
::
async_logger
::
_stop
()
inline
void
spdlog
::
async_logger
::
_stop
()
{
{
set_level
(
level
::
OFF
);
set_level
(
level
::
OFF
);
_as
->
shutdown
(
_shutdown_duration
);
_async_log_helper
->
shutdown
(
_shutdown_duration
);
}
inline
void
spdlog
::
async_logger
::
_log_msg
(
details
::
log_msg
&
msg
)
{
_async_log_helper
->
log
(
msg
);
}
}
include/spdlog/details/file_helper.h
View file @
df898267
...
@@ -102,7 +102,7 @@ public:
...
@@ -102,7 +102,7 @@ public:
size_t
size
=
msg
.
formatted
.
size
();
size_t
size
=
msg
.
formatted
.
size
();
auto
data
=
msg
.
formatted
.
data
();
auto
data
=
msg
.
formatted
.
data
();
if
(
std
::
fwrite
(
data
,
sizeof
(
char
)
,
size
,
_fd
)
!=
size
)
if
(
std
::
fwrite
(
data
,
1
,
size
,
_fd
)
!=
size
)
throw
spdlog_ex
(
"Failed writing to file "
+
_filename
);
throw
spdlog_ex
(
"Failed writing to file "
+
_filename
);
if
(
_auto_flush
)
if
(
_auto_flush
)
...
...
include/spdlog/details/format.cc
View file @
df898267
...
@@ -31,7 +31,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
...
@@ -31,7 +31,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#undef _SCL_SECURE_NO_WARNINGS
#undef _SCL_SECURE_NO_WARNINGS
#define _SCL_SECURE_NO_WARNINGS
#define _SCL_SECURE_NO_WARNINGS
#include "format.h"
#include <string.h>
#include <string.h>
...
...
include/spdlog/details/format.h
View file @
df898267
...
@@ -1050,7 +1050,7 @@ public:
...
@@ -1050,7 +1050,7 @@ public:
{
{
default:
default:
assert
(
false
);
assert
(
false
);
// Fall through.
// Fall through.
case
Arg
:
:
INT
:
case
Arg
:
:
INT
:
return
FMT_DISPATCH
(
visit_int
(
arg
.
int_value
));
return
FMT_DISPATCH
(
visit_int
(
arg
.
int_value
));
case
Arg
:
:
UINT
:
case
Arg
:
:
UINT
:
...
@@ -2219,7 +2219,7 @@ void BasicWriter<Char>::write_double(
...
@@ -2219,7 +2219,7 @@ void BasicWriter<Char>::write_double(
// MSVC's printf doesn't support 'F'.
// MSVC's printf doesn't support 'F'.
type
=
'f'
;
type
=
'f'
;
#endif
#endif
// Fall through.
// Fall through.
case
'E'
:
case
'E'
:
case
'G'
:
case
'G'
:
case
'A'
:
case
'A'
:
...
...
include/spdlog/details/log_msg.h
View file @
df898267
...
@@ -48,9 +48,13 @@ struct log_msg
...
@@ -48,9 +48,13 @@ struct log_msg
level
(
other
.
level
),
level
(
other
.
level
),
time
(
other
.
time
),
time
(
other
.
time
),
tm_time
(
other
.
tm_time
)
tm_time
(
other
.
tm_time
)
{
{
raw
.
write
(
other
.
raw
.
data
(),
other
.
raw
.
size
());
if
(
other
.
raw
.
size
())
formatted
.
write
(
other
.
formatted
.
data
(),
other
.
formatted
.
size
());
raw
<<
fmt
::
BasicStringRef
<
char
>
(
other
.
raw
.
data
(),
other
.
raw
.
size
());
if
(
other
.
formatted
.
size
())
formatted
<<
fmt
::
BasicStringRef
<
char
>
(
other
.
formatted
.
data
(),
other
.
formatted
.
size
());
}
}
log_msg
(
log_msg
&&
other
)
:
log_msg
(
log_msg
&&
other
)
:
...
...
include/spdlog/details/mpcs_q.h
View file @
df898267
#pragma once
/*************************************************************************/
/*
/*
M
odified version of Intrusive MPSC node-based queue
A m
odified version of Intrusive MPSC node-based queue
Original code from
Original code from
http://www.1024cores.net/home/lock-free-algorithms/queues/intrusive-mpsc-node-based-queue
http://www.1024cores.net/home/lock-free-algorithms/queues/intrusive-mpsc-node-based-queue
...
@@ -32,9 +30,10 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
...
@@ -32,9 +30,10 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those of the authors and
The views and conclusions contained in the software and documentation are those of the authors and
should not be interpreted as representing official policies, either expressed or implied, of Dmitry Vyukov.
should not be interpreted as representing official policies, either expressed or implied, of Dmitry Vyukov.
*/
/*************************************************************************/
/*************************************************************************/
/*
The code in its current form adds the license below:
*/
/*
******** The code in its current form adds the license below: *********
*/
/*************************************************************************/
/*************************************************************************/
/* spdlog - an extremely fast and easy to use c++11 logging library. */
/* spdlog - an extremely fast and easy to use c++11 logging library. */
/* Copyright (c) 2014 Gabi Melman. */
/* Copyright (c) 2014 Gabi Melman. */
...
@@ -59,6 +58,7 @@ should not be interpreted as representing official policies, either expressed or
...
@@ -59,6 +58,7 @@ should not be interpreted as representing official policies, either expressed or
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
/*************************************************************************/
#pragma once
#include <atomic>
#include <atomic>
namespace
spdlog
namespace
spdlog
...
@@ -70,35 +70,43 @@ class mpsc_q
...
@@ -70,35 +70,43 @@ class mpsc_q
{
{
public:
public:
mpsc_q
(
size_t
size
)
:
_stub
(
T
()),
_head
(
&
_stub
),
_tail
(
&
_stub
)
using
item_type
=
T
;
explicit
mpsc_q
(
size_t
max_size
)
:
_max_size
(
max_size
),
_size
(
0
),
_stub
(),
_head
(
&
_stub
),
_tail
(
&
_stub
)
{
{
_stub
.
next
=
nullptr
;
}
}
~
mpsc_q
()
mpsc_q
(
const
mpsc_q
&
)
=
delete
;
{
mpsc_q
&
operator
=
(
const
mpsc_q
&
)
=
delete
;
reset
();
}
void
reset
()
~
mpsc_q
()
{
{
T
dummy_val
;
clear
();
while
(
pop
(
dummy_val
));
}
}
bool
push
(
const
T
&
value
)
template
<
typename
TT
>
bool
push
(
TT
&&
value
)
{
{
mpscq_node_t
*
new_node
=
new
mpscq_node_t
(
value
);
if
(
_size
>=
_max_size
)
return
false
;
mpscq_node_t
*
new_node
=
new
mpscq_node_t
(
std
::
forward
<
TT
>
(
value
));
push_node
(
new_node
);
push_node
(
new_node
);
++
_size
;
return
true
;
return
true
;
}
}
// Try to pop or return false immediatly is queue is empty
bool
pop
(
T
&
value
)
bool
pop
(
T
&
value
)
{
{
mpscq_node_t
*
node
=
pop_node
();
mpscq_node_t
*
node
=
pop_node
();
if
(
node
!=
nullptr
)
if
(
node
!=
nullptr
)
{
{
value
=
node
->
value
;
--
_size
;
value
=
std
::
move
(
node
->
value
);
delete
(
node
);
delete
(
node
);
return
true
;
return
true
;
}
}
...
@@ -108,23 +116,49 @@ public:
...
@@ -108,23 +116,49 @@ public:
}
}
}
}
// Empty the queue by popping all its elements
void
clear
()
{
while
(
mpscq_node_t
*
node
=
pop_node
())
{
--
_size
;
delete
(
node
);
}
}
// Return approx size
size_t
approx_size
()
const
{
return
_size
.
load
();
}
private:
private:
struct
mpscq_node_t
struct
mpscq_node_t
{
{
std
::
atomic
<
mpscq_node_t
*>
next
;
std
::
atomic
<
mpscq_node_t
*>
next
;
T
value
;
T
value
;
explicit
mpscq_node_t
(
const
T
&
value
)
:
next
(
nullptr
),
value
(
value
)
mpscq_node_t
()
:
next
(
nullptr
)
{}
{
mpscq_node_t
(
const
mpscq_node_t
&
)
=
delete
;
}
mpscq_node_t
&
operator
=
(
const
mpscq_node_t
&
)
=
delete
;
explicit
mpscq_node_t
(
const
T
&
value
)
:
next
(
nullptr
),
value
(
value
)
{}
explicit
mpscq_node_t
(
T
&&
value
)
:
next
(
nullptr
),
value
(
std
::
move
(
value
))
{}
};
};
size_t
_max_size
;
std
::
atomic
<
size_t
>
_size
;
mpscq_node_t
_stub
;
mpscq_node_t
_stub
;
std
::
atomic
<
mpscq_node_t
*>
_head
;
std
::
atomic
<
mpscq_node_t
*>
_head
;
mpscq_node_t
*
_tail
;
mpscq_node_t
*
_tail
;
// Lockfree push
void
push_node
(
mpscq_node_t
*
n
)
void
push_node
(
mpscq_node_t
*
n
)
{
{
n
->
next
=
nullptr
;
n
->
next
=
nullptr
;
...
@@ -132,6 +166,8 @@ private:
...
@@ -132,6 +166,8 @@ private:
prev
->
next
=
n
;
prev
->
next
=
n
;
}
}
// Clever lockfree pop algorithm by Dmitry Vyukov using single xchng instruction..
// Return pointer to the poppdc node or nullptr if no items left in the queue
mpscq_node_t
*
pop_node
()
mpscq_node_t
*
pop_node
()
{
{
mpscq_node_t
*
tail
=
_tail
;
mpscq_node_t
*
tail
=
_tail
;
...
@@ -151,7 +187,7 @@ private:
...
@@ -151,7 +187,7 @@ private:
}
}
mpscq_node_t
*
head
=
_head
;
mpscq_node_t
*
head
=
_head
;
if
(
tail
!=
head
)
if
(
tail
!=
head
)
return
0
;
return
nullptr
;
push_node
(
&
_stub
);
push_node
(
&
_stub
);
next
=
tail
->
next
;
next
=
tail
->
next
;
...
@@ -163,8 +199,6 @@ private:
...
@@ -163,8 +199,6 @@ private:
return
nullptr
;
return
nullptr
;
}
}
};
};
}
}
}
}
\ No newline at end of file
include/spdlog/details/pattern_formatter_impl.h
View file @
df898267
...
@@ -345,7 +345,7 @@ class v_formatter :public flag_formatter
...
@@ -345,7 +345,7 @@ class v_formatter :public flag_formatter
{
{
void
format
(
details
::
log_msg
&
msg
)
override
void
format
(
details
::
log_msg
&
msg
)
override
{
{
msg
.
formatted
.
write
(
msg
.
raw
.
data
(),
msg
.
raw
.
size
());
msg
.
formatted
<<
fmt
::
StringRef
(
msg
.
raw
.
data
(),
msg
.
raw
.
size
());
}
}
};
};
...
@@ -404,16 +404,16 @@ class full_formatter :public flag_formatter
...
@@ -404,16 +404,16 @@ class full_formatter :public flag_formatter
msg.raw.str());*/
msg.raw.str());*/
// Faster (albeit uglier) way to format the line (5.6 million lines/sec under 10 threads)
// Faster (albeit uglier) way to format the line (5.6 million lines/sec under 10 threads)
msg
.
formatted
<<
'['
<<
msg
.
tm_time
.
tm_year
+
1900
<<
'-'
msg
.
formatted
<<
'['
<<
static_cast
<
unsigned
int
>
(
msg
.
tm_time
.
tm_year
+
1900
)
<<
'-'
<<
fmt
::
pad
(
msg
.
tm_time
.
tm_mon
+
1
,
2
,
'0'
)
<<
'-'
<<
fmt
::
pad
(
static_cast
<
unsigned
int
>
(
msg
.
tm_time
.
tm_mon
+
1
)
,
2
,
'0'
)
<<
'-'
<<
fmt
::
pad
(
msg
.
tm_time
.
tm_mday
,
2
,
'0'
)
<<
' '
<<
fmt
::
pad
(
static_cast
<
unsigned
int
>
(
msg
.
tm_time
.
tm_mday
)
,
2
,
'0'
)
<<
' '
<<
fmt
::
pad
(
msg
.
tm_time
.
tm_hour
,
2
,
'0'
)
<<
':'
<<
fmt
::
pad
(
static_cast
<
unsigned
int
>
(
msg
.
tm_time
.
tm_hour
)
,
2
,
'0'
)
<<
':'
<<
fmt
::
pad
(
msg
.
tm_time
.
tm_min
,
2
,
'0'
)
<<
':'
<<
fmt
::
pad
(
static_cast
<
unsigned
int
>
(
msg
.
tm_time
.
tm_min
)
,
2
,
'0'
)
<<
':'
<<
fmt
::
pad
(
msg
.
tm_time
.
tm_sec
,
2
,
'0'
)
<<
'.'
<<
fmt
::
pad
(
static_cast
<
unsigned
int
>
(
msg
.
tm_time
.
tm_sec
)
,
2
,
'0'
)
<<
'.'
<<
fmt
::
pad
(
static_cast
<
int
>
(
millis
),
3
,
'0'
)
<<
"] "
;
<<
fmt
::
pad
(
static_cast
<
unsigned
int
>
(
millis
),
3
,
'0'
)
<<
"] "
;
msg
.
formatted
<<
'['
<<
msg
.
logger_name
<<
"] ["
<<
level
::
to_str
(
msg
.
level
)
<<
"] "
;
msg
.
formatted
<<
'['
<<
msg
.
logger_name
<<
"] ["
<<
level
::
to_str
(
msg
.
level
)
<<
"] "
;
msg
.
formatted
.
write
(
msg
.
raw
.
data
(),
msg
.
raw
.
size
());
msg
.
formatted
<<
fmt
::
StringRef
(
msg
.
raw
.
data
(),
msg
.
raw
.
size
());
}
}
};
};
...
@@ -460,7 +460,7 @@ inline void spdlog::pattern_formatter::handle_flag(char flag)
...
@@ -460,7 +460,7 @@ inline void spdlog::pattern_formatter::handle_flag(char flag)
{
{
switch
(
flag
)
switch
(
flag
)
{
{
// logger name
// logger name
case
'n'
:
case
'n'
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
name_formatter
()));
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
name_formatter
()));
break
;
break
;
...
@@ -581,7 +581,7 @@ inline void spdlog::pattern_formatter::format(details::log_msg& msg)
...
@@ -581,7 +581,7 @@ inline void spdlog::pattern_formatter::format(details::log_msg& msg)
f
->
format
(
msg
);
f
->
format
(
msg
);
}
}
//write eol
//write eol
msg
.
formatted
.
write
(
details
::
os
::
eol
(),
details
::
os
::
eol_size
()
);
msg
.
formatted
<<
details
::
os
::
eol
(
);
}
}
catch
(
const
fmt
::
FormatError
&
e
)
catch
(
const
fmt
::
FormatError
&
e
)
{
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment