Skip to content
Open
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
9 changes: 5 additions & 4 deletions Framework/AnalysisSupport/src/TTreePlugin.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#include "Framework/RootArrowFilesystem.h"
#include "Framework/Plugins.h"
#include "Framework/Signpost.h"
#include "Framework/Endian.h"
#include "Framework/BigEndian.h"
#include <TBufferFile.h>
#include <TBufferIO.h>
#include <arrow/buffer.h>
Expand Down Expand Up @@ -197,7 +197,7 @@ auto readValues = [](uint8_t* target, ReadOps& op, TBufferFile& rootBuffer) {
}
int size = readLast * op.listSize;
readEntries += readLast;
swapCopy(target, rootBuffer.GetCurrent(), size, op.typeSize);
bigEndianCopy(target, rootBuffer.GetCurrent(), size, op.typeSize);
target += (ptrdiff_t)(size * op.typeSize);
}
};
Expand Down Expand Up @@ -230,7 +230,7 @@ auto readVLAValues = [](uint8_t* target, ReadOps& op, ReadOps const& offsetOp, T
auto readLast = op.branch->GetBulkRead().GetEntriesSerialized(readEntries, rootBuffer);
int size = offsets[readEntries + readLast] - offsets[readEntries];
readEntries += readLast;
swapCopy(target, rootBuffer.GetCurrent(), size, op.typeSize);
bigEndianCopy(target, rootBuffer.GetCurrent(), size, op.typeSize);
target += (ptrdiff_t)(size * op.typeSize);
}
};
Expand Down Expand Up @@ -581,7 +581,8 @@ auto readOffsets = [](ReadOps& op, TBufferFile& rootBuffer) {
readEntries += readLast;
for (auto i = 0; i < readLast; ++i) {
offsets[count++] = (int)offset;
offset += swap32_(reinterpret_cast<uint32_t*>(rootBuffer.GetCurrent())[i]);
uint32_t raw = reinterpret_cast<uint32_t*>(rootBuffer.GetCurrent())[i];
offset += (std::endian::native == std::endian::little) ? __builtin_bswap32(raw) : raw;
}
}
offsets[count] = (int)offset;
Expand Down
1 change: 0 additions & 1 deletion Framework/AnalysisSupport/src/TableTreeHelpers.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
// or submit itself to any jurisdiction.
#include "Framework/TableTreeHelpers.h"
#include "Framework/Logger.h"
#include "Framework/Endian.h"
#include "Framework/Signpost.h"

#include <arrow/dataset/file_base.h>
Expand Down
1 change: 0 additions & 1 deletion Framework/Core/src/FragmentToBatch.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
// or submit itself to any jurisdiction.
#include "Framework/FragmentToBatch.h"
#include "Framework/Logger.h"
#include "Framework/Endian.h"
#include "Framework/Signpost.h"

#include <arrow/dataset/file_base.h>
Expand Down
24 changes: 12 additions & 12 deletions Framework/Core/src/HTTPParser.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ void encode_websocket_frames(std::vector<uv_buf_t>& outputs, char const* src, si
int maskSize = mask ? 4 : 0;

if (size < 126) {
headerSize = sizeof(WebSocketFrameTiny);
headerSize = sizeof(WebSocketFrameTiny<std::endian::native>);
// Allocate a new page if we do not fit in the current one
if (outputs.empty() || outputs.back().len > WebSocketConstants::MaxChunkSize || (size + maskSize + headerSize) > (WebSocketConstants::MaxChunkSize - outputs.back().len)) {
char* chunk = (char*)malloc(WebSocketConstants::MaxChunkSize);
Expand All @@ -64,11 +64,11 @@ void encode_websocket_frames(std::vector<uv_buf_t>& outputs, char const* src, si
// Reposition the buffer to the end of the current page
buffer = buf.base + buf.len;
buf.len += headerSize + size + maskSize;
WebSocketFrameTiny* header = (WebSocketFrameTiny*)buffer;
auto* header = (WebSocketFrameTiny<std::endian::native>*)buffer;
memset(buffer, 0, headerSize);
header->len = size;
} else if (size < 1 << 16) {
headerSize = sizeof(WebSocketFrameShort);
headerSize = sizeof(WebSocketFrameShort<std::endian::native>);
// Allocate a new page if we do not fit in the current one
if (outputs.empty() || outputs.back().len > WebSocketConstants::MaxChunkSize || (size + maskSize + headerSize) > (WebSocketConstants::MaxChunkSize - outputs.back().len)) {
char* chunk = (char*)malloc(WebSocketConstants::MaxChunkSize);
Expand All @@ -78,24 +78,24 @@ void encode_websocket_frames(std::vector<uv_buf_t>& outputs, char const* src, si
// Reposition the buffer to the end of the current page
buffer = buf.base + buf.len;
buf.len += headerSize + size + maskSize;
WebSocketFrameShort* header = (WebSocketFrameShort*)buffer;
auto* header = (WebSocketFrameShort<std::endian::native>*)buffer;
memset(buffer, 0, headerSize);
header->len = 126;
header->len16 = htons(size);
} else {
// For larger messages we do standalone allocation
// so that the message does not need to be sent in multiple chunks
headerSize = sizeof(WebSocketFrameHuge);
headerSize = sizeof(WebSocketFrameHuge<std::endian::native>);
buffer = (char*)malloc(headerSize + maskSize + size);
WebSocketFrameHuge* header = (WebSocketFrameHuge*)buffer;
auto* header = (WebSocketFrameHuge<std::endian::native>*)buffer;
memset(buffer, 0, headerSize);
header->len = 127;
header->len64 = htonll(size);
header->len64 = (std::endian::native == std::endian::little) ? __builtin_bswap64(size) : size;
outputs.push_back(uv_buf_init(buffer, size + maskSize + headerSize));
}
size_t fullHeaderSize = maskSize + headerSize;
startPayload = buffer + fullHeaderSize;
WebSocketFrameTiny* header = (WebSocketFrameTiny*)buffer;
auto* header = (WebSocketFrameTiny<std::endian::native>*)buffer;
header->fin = 1;
header->opcode = (unsigned char)opcode; // binary or text for now
// Mask is right before payload.
Expand Down Expand Up @@ -143,7 +143,7 @@ void decode_websocket(char* start, size_t size, WebSocketHandler& handler)
handler.beginChunk();
// The + 2 is there because we need at least 2 bytes.
while (cur - start < size) {
WebSocketFrameTiny* header = (WebSocketFrameTiny*)cur;
auto* header = (WebSocketFrameTiny<std::endian::native>*)cur;
size_t payloadSize = 0;
size_t headerSize = 0;
if ((cur + 2 - start >= size) ||
Expand All @@ -160,12 +160,12 @@ void decode_websocket(char* start, size_t size, WebSocketHandler& handler)
payloadSize = header->len;
headerSize = 2 + (header->mask ? 4 : 0);
} else if (header->len == 126) {
WebSocketFrameShort* headerSmall = (WebSocketFrameShort*)cur;
auto* headerSmall = (WebSocketFrameShort<std::endian::native>*)cur;
payloadSize = ntohs(headerSmall->len16);
headerSize = 2 + 2 + (header->mask ? 4 : 0);
} else if (header->len == 127) {
WebSocketFrameHuge* headerSmall = (WebSocketFrameHuge*)cur;
payloadSize = ntohll(headerSmall->len64);
auto* headerSmall = (WebSocketFrameHuge<std::endian::native>*)cur;
payloadSize = (std::endian::native == std::endian::little) ? __builtin_bswap64(headerSmall->len64) : headerSmall->len64;
headerSize = 2 + 8 + (header->mask ? 4 : 0);
}
size_t availableSize = size - (cur - start);
Expand Down
72 changes: 42 additions & 30 deletions Framework/Core/src/HTTPParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
#ifndef O2_FRAMEWORK_HTTPPARSER_H_
#define O2_FRAMEWORK_HTTPPARSER_H_

#include "Framework/Endian.h"
#include <bit>
#include <cstdint>
#include <fmt/format.h>
#include <uv.h>
#include <string>
Expand All @@ -22,71 +23,82 @@
namespace o2::framework
{

struct __attribute__((__packed__)) WebSocketFrameTiny {
#if O2_HOST_BYTE_ORDER == O2_LITTLE_ENDIAN
template <std::endian E>
struct __attribute__((__packed__)) WebSocketFrameTiny;

template <>
struct __attribute__((__packed__)) WebSocketFrameTiny<std::endian::little> {
unsigned char opcode : 4;
unsigned char rsv3 : 1;
unsigned char rsv2 : 1;
unsigned char rsv1 : 1;
unsigned char fin : 1;
unsigned char len : 7;
unsigned char mask : 1;
#elif O2_HOST_BYTE_ORDER == O2_BIG_ENDIAN
};

template <>
struct __attribute__((__packed__)) WebSocketFrameTiny<std::endian::big> {
unsigned char fin : 1;
unsigned char rsv1 : 1;
unsigned char rsv2 : 1;
unsigned char rsv3 : 1;
unsigned char opcode : 4;
unsigned char mask : 1;
unsigned char len : 7;
#else
#error Uknown endiannes
#endif
};

struct __attribute__((__packed__)) WebSocketFrameShort {
#if O2_HOST_BYTE_ORDER == O2_LITTLE_ENDIAN
template <std::endian E>
struct __attribute__((__packed__)) WebSocketFrameShort;

template <>
struct __attribute__((__packed__)) WebSocketFrameShort<std::endian::little> {
unsigned char opcode : 4;
unsigned char rsv3 : 1;
unsigned char rsv2 : 1;
unsigned char rsv1 : 1;
unsigned char fin : 1;
unsigned char len : 7;
unsigned char mask : 1;
#elif O2_HOST_BYTE_ORDER == O2_BIG_ENDIAN
uint16_t len16;
};

template <>
struct __attribute__((__packed__)) WebSocketFrameShort<std::endian::big> {
unsigned char fin : 1;
unsigned char rsv1 : 1;
unsigned char rsv2 : 1;
unsigned char rsv3 : 1;
unsigned char opcode : 4;
unsigned char mask : 1;
unsigned char len : 7;
#else
#error Uknown endiannes
#endif
uint16_t len16;
};

struct __attribute__((__packed__)) WebSocketFrameHuge {
#if O2_HOST_BYTE_ORDER == O2_LITTLE_ENDIAN
template <std::endian E>
struct __attribute__((__packed__)) WebSocketFrameHuge;

template <>
struct __attribute__((__packed__)) WebSocketFrameHuge<std::endian::little> {
unsigned char opcode : 4;
unsigned char rsv3 : 1;
unsigned char rsv2 : 1;
unsigned char rsv1 : 1;
unsigned char fin : 1;
unsigned char len : 7;
unsigned char mask : 1;
#elif O2_HOST_BYTE_ORDER == O2_BIG_ENDIAN
uint64_t len64;
};

template <>
struct __attribute__((__packed__)) WebSocketFrameHuge<std::endian::big> {
unsigned char fin : 1;
unsigned char rsv1 : 1;
unsigned char rsv2 : 1;
unsigned char rsv3 : 1;
unsigned char opcode : 4;
unsigned char mask : 1;
unsigned char len : 7;
#else
#error Uknown endiannes
#endif
uint64_t len64;
};

Expand Down Expand Up @@ -138,9 +150,9 @@ struct WebSocketHandler {
virtual ~WebSocketHandler() = default;

/// Invoked when all the headers are received.
virtual void headers(std::map<std::string, std::string> const& headers){};
virtual void headers(std::map<std::string, std::string> const& headers) {};
/// FIXME: not implemented
virtual void beginFragmentation(){};
virtual void beginFragmentation() {};
/// Invoked when a frame it's parsed. Notice you do not own the data and you must
/// not free the memory.
virtual void frame(char const* frame, size_t s) {}
Expand Down Expand Up @@ -205,18 +217,18 @@ struct HTTPParser {
std::string remaining;
std::string error;
std::vector<HTTPState> states;
virtual void method(std::string_view const& s){};
virtual void target(std::string_view const& s){};
virtual void version(std::string_view const& s){};
virtual void header(std::string_view const& k, std::string_view const& v){};
virtual void endHeaders(){};
virtual void method(std::string_view const& s) {};
virtual void target(std::string_view const& s) {};
virtual void version(std::string_view const& s) {};
virtual void header(std::string_view const& k, std::string_view const& v) {};
virtual void endHeaders() {};
/// Invoked whenever we are parsing data.
/// In order to allow for xoring (as required by the websocket standard)
/// in place, we pass it as a mutable pointer.
virtual void body(char* data, size_t s){};
virtual void replyVersion(std::string_view const& s){};
virtual void replyCode(std::string_view const& s){};
virtual void replyMessage(std::string_view const& s){};
virtual void body(char* data, size_t s) {};
virtual void replyVersion(std::string_view const& s) {};
virtual void replyCode(std::string_view const& s) {};
virtual void replyMessage(std::string_view const& s) {};
};

struct HTTPParserHelpers {
Expand Down
9 changes: 8 additions & 1 deletion Framework/Foundation/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ add_executable(o2-test-framework-foundation
test/test_CallbackRegistry.cxx
test/test_CompilerBuiltins.cxx
# test/test_Signpost.cxx
test/test_RuntimeError.cxx)
test/test_RuntimeError.cxx
test/test_BigEndian.cxx)
target_link_libraries(o2-test-framework-foundation PRIVATE O2::FrameworkFoundation)
target_link_libraries(o2-test-framework-foundation PRIVATE O2::Catch2)

Expand Down Expand Up @@ -65,4 +66,10 @@ install(TARGETS o2-log RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})

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

add_executable(o2-benchmark-framework-BigEndian
test/benchmark_BigEndian.cxx)
target_link_libraries(o2-benchmark-framework-BigEndian
PRIVATE O2::FrameworkFoundation benchmark::benchmark)
set_property(TARGET o2-benchmark-framework-BigEndian PROPERTY RUNTIME_OUTPUT_DIRECTORY ${outdir})

add_subdirectory(3rdparty)
64 changes: 64 additions & 0 deletions Framework/Foundation/include/Framework/BigEndian.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright 2019-2026 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.

#ifndef O2_FRAMEWORK_BIGENDIAN_H_
#define O2_FRAMEWORK_BIGENDIAN_H_

#include <bit>
#include <cstddef>
#include <cstdint>
#include <cstring>

namespace o2::framework
{

/// Copy @a count elements of @a typeSize bytes each from big-endian @a src
/// into native byte order at @a dest. For typeSize == 1 or on big-endian
/// platforms this reduces to a plain memcpy. @a dest and @a src must not overlap.
inline void bigEndianCopy(void* dest, const void* src, int count, size_t typeSize)
{
auto const totalBytes = static_cast<size_t>(count) * typeSize;
if constexpr (std::endian::native == std::endian::big) {
std::memcpy(dest, src, totalBytes);
return;
}
switch (typeSize) {
case 2: {
auto* p = static_cast<uint16_t*>(dest);
auto* q = static_cast<const uint16_t*>(src);
for (int i = 0; i < count; ++i) {
p[i] = __builtin_bswap16(q[i]);
}
return;
}
case 4: {
auto* p = static_cast<uint32_t*>(dest);
auto* q = static_cast<const uint32_t*>(src);
for (int i = 0; i < count; ++i) {
p[i] = __builtin_bswap32(q[i]);
}
return;
}
case 8: {
auto* p = static_cast<uint64_t*>(dest);
auto* q = static_cast<const uint64_t*>(src);
for (int i = 0; i < count; ++i) {
p[i] = __builtin_bswap64(q[i]);
}
return;
}
}
std::memcpy(dest, src, totalBytes);
}

} // namespace o2::framework

#endif // O2_FRAMEWORK_BIGENDIAN_H_
Loading