Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Please consider the following formatting changes to #11779 #210

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Framework/Foundation/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/include/Framework

o2_add_library(FrameworkFoundation
SOURCES src/RuntimeError.cxx
src/Signpost.cxx
TARGETVARNAME targetName
PUBLIC_LINK_LIBRARIES O2::FrameworkFoundation3rdparty
)
Expand All @@ -39,9 +40,14 @@ add_executable(o2-test-framework-Signpost
test/test_Signpost.cxx)
target_link_libraries(o2-test-framework-Signpost PRIVATE O2::FrameworkFoundation)

add_executable(o2-test-framework-SignpostLogger
test/test_SignpostLogger.cxx)
target_link_libraries(o2-test-framework-SignpostLogger PRIVATE O2::FrameworkFoundation)

get_filename_component(outdir ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/../tests ABSOLUTE)
set_property(TARGET o2-test-framework-foundation PROPERTY RUNTIME_OUTPUT_DIRECTORY ${outdir})
set_property(TARGET o2-test-framework-Signpost PROPERTY RUNTIME_OUTPUT_DIRECTORY ${outdir})
set_property(TARGET o2-test-framework-SignpostLogger PROPERTY RUNTIME_OUTPUT_DIRECTORY ${outdir})

add_test(NAME framework:foundation COMMAND o2-test-framework-foundation)

Expand Down
145 changes: 82 additions & 63 deletions Framework/Foundation/include/Framework/Signpost.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,77 +55,18 @@
// the signpost information to the log.
#include <atomic>
#include <array>
#include <cstdio>
#include "Framework/RuntimeError.h"

#include <cassert>
#include <atomic>
#include <cstdarg>
#include <cinttypes>
#include <cstddef>

namespace {
namespace
{
struct _o2_lock_free_stack {
static constexpr size_t N = 1024;
std::atomic<size_t> top = 0;
int stack[N];
};

// returns true if the push was successful, false if the stack was full
// @param spin if true, will spin until the stack is not full
bool _o2_lock_free_stack_push(_o2_lock_free_stack& stack, const int& value, bool spin = false)
{
size_t currentTop = stack.top.load(std::memory_order_relaxed);
while (true) {
if (currentTop == _o2_lock_free_stack::N && spin == false) {
return false;
} else if (currentTop == _o2_lock_free_stack::N) {
// Avoid consuming too much CPU time if we are spinning.
#if defined(__x86_64__) || defined(__i386__)
__asm__ __volatile__("pause" ::
: "memory");
#elif defined(__aarch64__)
__asm__ __volatile__("yield" ::
: "memory");
#endif
continue;
}

if (stack.top.compare_exchange_weak(currentTop, currentTop + 1,
std::memory_order_release,
std::memory_order_relaxed)) {
stack.stack[currentTop] = value;
return true;
}
}
}

bool _o2_lock_free_stack_pop(_o2_lock_free_stack& stack, int& value, bool spin = false)
{
size_t currentTop = stack.top.load(std::memory_order_relaxed);
while (true) {
if (currentTop == 0 && spin == false) {
return false;
} else if (currentTop == 0) {
// Avoid consuming too much CPU time if we are spinning.
#if defined(__x86_64__) || defined(__i386__)
__asm__ __volatile__("pause" ::
: "memory");
#elif defined(__aarch64__)
__asm__ __volatile__("yield" ::
: "memory");
#endif
continue;
}

if (stack.top.compare_exchange_weak(currentTop, currentTop - 1,
std::memory_order_acquire,
std::memory_order_relaxed)) {
value = stack.stack[currentTop - 1];
return true;
}
}
}

// A log is simply an inbox which keeps track of the available id, so that we can print out different signposts
// with different indentation levels.
// supports up to 1024 paralle signposts before it spinlocks.
Expand Down Expand Up @@ -162,6 +103,18 @@ struct _o2_log_t {
std::atomic<int> stacktrace = 1;
};

bool _o2_lock_free_stack_push(_o2_lock_free_stack& stack, const int& value, bool spin = false);
bool _o2_lock_free_stack_pop(_o2_lock_free_stack& stack, int& value, bool spin = false);
//_o2_signpost_id_t _o2_signpost_id_generate_local(_o2_log_t* log);
//_o2_signpost_id_t _o2_signpost_id_make_with_pointer(_o2_log_t* log, void* pointer);
_o2_signpost_index_t o2_signpost_id_make_with_pointer(_o2_log_t* log, void* pointer);
_o2_log_t* _o2_log_create(char const* name, int stacktrace);
void _o2_signpost_event_emit(_o2_log_t* log, _o2_signpost_id_t id, char const* name, char const* const format, ...);
void _o2_signpost_interval_begin(_o2_log_t* log, _o2_signpost_id_t id, char const* name, char const* const format, ...);
void _o2_signpost_interval_end_v(_o2_log_t* log, _o2_signpost_id_t id, char const* name, char const* const format, va_list args);
void _o2_signpost_interval_end(_o2_log_t* log, _o2_signpost_id_t id, char const* name, char const* const format, ...);
void _o2_log_set_stacktrace(_o2_log_t* log, int stacktrace);

// This generates a unique id for a signpost. Do not use this directly, use O2_SIGNPOST_ID_GENERATE instead.
// Notice that this is only valid on a given computer.
// This is guaranteed to be unique at 5 GHz for at least 63 years, if my math is correct.
Expand Down Expand Up @@ -190,6 +143,71 @@ inline _o2_signpost_index_t o2_signpost_id_make_with_pointer(_o2_log_t* log, voi
log->ids[signpost_index].id = (int64_t)pointer;
return signpost_index;
}
} // namespace

// Implementation start here. Include this file with O2_SIGNPOST_IMPLEMENTATION defined in one file of your
// project.
#ifdef O2_SIGNPOST_IMPLEMENTATION
#include <cstdarg>
#include <cstdio>
#include "Framework/RuntimeError.h"
namespace
{
// returns true if the push was successful, false if the stack was full
// @param spin if true, will spin until the stack is not full
bool _o2_lock_free_stack_push(_o2_lock_free_stack& stack, const int& value, bool spin)
{
size_t currentTop = stack.top.load(std::memory_order_relaxed);
while (true) {
if (currentTop == _o2_lock_free_stack::N && spin == false) {
return false;
} else if (currentTop == _o2_lock_free_stack::N) {
// Avoid consuming too much CPU time if we are spinning.
#if defined(__x86_64__) || defined(__i386__)
__asm__ __volatile__("pause" ::
: "memory");
#elif defined(__aarch64__)
__asm__ __volatile__("yield" ::
: "memory");
#endif
continue;
}

if (stack.top.compare_exchange_weak(currentTop, currentTop + 1,
std::memory_order_release,
std::memory_order_relaxed)) {
stack.stack[currentTop] = value;
return true;
}
}
}

bool _o2_lock_free_stack_pop(_o2_lock_free_stack& stack, int& value, bool spin)
{
size_t currentTop = stack.top.load(std::memory_order_relaxed);
while (true) {
if (currentTop == 0 && spin == false) {
return false;
} else if (currentTop == 0) {
// Avoid consuming too much CPU time if we are spinning.
#if defined(__x86_64__) || defined(__i386__)
__asm__ __volatile__("pause" ::
: "memory");
#elif defined(__aarch64__)
__asm__ __volatile__("yield" ::
: "memory");
#endif
continue;
}

if (stack.top.compare_exchange_weak(currentTop, currentTop - 1,
std::memory_order_acquire,
std::memory_order_relaxed)) {
value = stack.stack[currentTop - 1];
return true;
}
}
}

_o2_log_t* _o2_log_create(char const* name, int stacktrace)
{
Expand Down Expand Up @@ -318,7 +336,8 @@ void _o2_log_set_stacktrace(_o2_log_t* log, int stacktrace)
{
log->stacktrace = stacktrace;
}
}
} // anonymous namespace
#endif // O2_SIGNPOST_IMPLEMENTATION

/// Dynamic logs need to be enabled via the O2_LOG_ENABLE_DYNAMIC macro. Notice this will only work
/// for the logger based logging, since the Apple version needs instruments to enable them.
Expand Down
13 changes: 13 additions & 0 deletions Framework/Foundation/src/Signpost.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
// All rights not expressly granted are reserved.
//
// This software is distributed under the terms of the GNU General Public
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
//
// In applying this license CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

#define O2_SIGNPOST_IMPLEMENTATION
#include "Framework/Signpost.h"
1 change: 0 additions & 1 deletion Framework/Foundation/test/test_Signpost.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

#define O2_FORCE_LOGGER_SIGNPOST 1
#include "Framework/Signpost.h"
#include <iostream>

Expand Down
49 changes: 49 additions & 0 deletions Framework/Foundation/test/test_SignpostLogger.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
// All rights not expressly granted are reserved.
//
// This software is distributed under the terms of the GNU General Public
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
//
// In applying this license CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

#ifdef __APPLE__
#define O2_SIGNPOST_IMPLEMENTATION
#endif
#define O2_FORCE_LOGGER_SIGNPOST 1
#include "Framework/Signpost.h"
#include <iostream>

int main(int argc, char** argv)
{
O2_DECLARE_LOG(test_Signpost, "my category");
O2_DECLARE_DYNAMIC_LOG(test_SignpostDynamic);

O2_LOG_DEBUG(test_Signpost, "%s %d", "test_Signpost", 1);
O2_SIGNPOST_ID_GENERATE(id, test_Signpost);
O2_SIGNPOST_ID_GENERATE(id2, test_Signpost);
O2_SIGNPOST_START(test_Signpost, id, "Test category", "This is a test signpost");
O2_SIGNPOST_START(test_Signpost, id2, "Test category", "A sepaarate interval");
O2_SIGNPOST_EVENT_EMIT(test_Signpost, id, "Test category", "An event in an interval");
O2_SIGNPOST_END(test_Signpost, id, "Test category", "End of the first interval");
O2_SIGNPOST_END(test_Signpost, id2, "Test category", "A sepaarate interval");
O2_SIGNPOST_ID_FROM_POINTER(id3, test_Signpost, &id2);
O2_SIGNPOST_START(test_Signpost, id3, "Test category", "A signpost interval from a pointer");
O2_SIGNPOST_END(test_Signpost, id3, "Test category", "A signpost interval from a pointer");

// This has an engineering type, which we will not use on Linux / FairLogger
O2_SIGNPOST_ID_FROM_POINTER(id4, test_Signpost, &id3);
O2_SIGNPOST_START(test_Signpost, id4, "Test category", "A signpost with an engineering type formatter " O2_ENG_TYPE(size - in - bytes, "d"), 1);
O2_SIGNPOST_END(test_Signpost, id4, "Test category", "A signpost interval from a pointer");

O2_SIGNPOST_START(test_SignpostDynamic, id, "Test category", "This is dynamic signpost which you will not see, because they are off by default");
O2_SIGNPOST_END(test_SignpostDynamic, id, "Test category", "This is dynamic signpost which you will not see, because they are off by default");
O2_LOG_ENABLE_DYNAMIC(test_SignpostDynamic);
#ifdef __APPLE__
// On Apple there is no way to turn on signposts in the logger, so we do not display this message
O2_SIGNPOST_START(test_SignpostDynamic, id, "Test category", "This is dynamic signpost which you will see, because we turned them on");
O2_SIGNPOST_END(test_SignpostDynamic, id, "Test category", "This is dynamic signpost which you will see, because we turned them on");
#endif
}