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

Change the use of rte_ring for dumping in/out/drop packets to a newer… #155

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

yevzman
Copy link

@yevzman yevzman commented Apr 4, 2024

… approach

@yevzman yevzman requested a review from taitov as a code owner April 4, 2024 22:43
@@ -39,6 +39,8 @@
#include "sock_dev.h"
#include "worker.h"

#define MAX_PACK_SIZE 16384
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I know, we don't have any coding style document apart from .clang-format which should specify such things. However, if we strive to use "modern C++", we shouldn't use macros.

From C++ Core Guidelines, part ES.31:
Don’t use macros for constants or “functions”
Reason
Macros are a major source of bugs. Macros don’t obey the usual scope and type rules. Macros don’t obey the usual rules for argument passing. Macros ensure that the human reader sees something different from what the compiler sees. Macros complicate tool building.

Here we could use constexpr unsigned long max_pack_size = 16384; or maybe constexpr auto MY_CONSTANT{42}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At least we should move the definition to common/config.release.h where it will be look more consistent.

}
const auto units_number = getConfigValues().ring_lowPriority_size;
const auto size = sizeof(sharedmemory::ring_header_t) + unit_size * units_number;
ring.init(memaddr, unit_size, units_number);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, I don't know if we allow or prohibit this, but C++ Core Guidelines tells us "ES.46: Avoid lossy (narrowing, truncating) arithmetic conversions".
This is a narrowing conversion from 'unsigned long' to signed type 'int' for both unit_size and units_member.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch

Comment on lines +1351 to +1372
// init lowPriority ring
{
auto name = "r_lp_" + std::to_string(core_id);
auto offset = offsets[shm];
auto memaddr = (void*)((intptr_t)shm + offset);
sharedmemory::cSharedMemory ring;

auto unit_size = sizeof(sharedmemory::item_header_t) + MAX_PACK_SIZE;
if (unit_size % RTE_CACHE_LINE_SIZE != 0)
{
unit_size += RTE_CACHE_LINE_SIZE - unit_size % RTE_CACHE_LINE_SIZE; /// round up
}
const auto units_number = getConfigValues().ring_lowPriority_size;
const auto size = sizeof(sharedmemory::ring_header_t) + unit_size * units_number;
ring.init(memaddr, unit_size, units_number);
offsets[shm] += size;

worker->lowPriorityRing = ring;

auto meta = common::idp::get_shm_info::dump_meta(name, "lp", unit_size, units_number, core_id, socket_id, key, offset);
dumps_meta.emplace_back(meta);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This almost looks like a previous block of code (body of for (const auto& [tag, ring_cfg] : config.shared_memory) loop).
I think we could extract common functionality to a function.
something like:

  void foo(arguments)
  {
      auto name = base_name + std::to_string(core_id) + (is_low_priority ? "" : "_" + std::to_string(ring_id));
  
      auto unit_size = sizeof(sharedmemory::item_header_t) + dump_size;
      if (unit_size % RTE_CACHE_LINE_SIZE != 0)
      {
          unit_size += RTE_CACHE_LINE_SIZE - unit_size % RTE_CACHE_LINE_SIZE;
      }
  
      auto size = sizeof(sharedmemory::ring_header_t) + unit_size * units_number;
      auto offset = offsets[shm];
      auto memaddr = reinterpret_cast<void*>(reinterpret_cast<std::uintptr_t>(shm) + offset);
  
      sharedmemory::cSharedMemory ring;
      ring.init(memaddr, unit_size, units_number);
      offsets[shm] += size;
  
      auto meta = common::idp::get_shm_info::dump_meta(name, tag, unit_size, units_number, core_id, socket_id, key, offset);
      dumps_meta.emplace_back(meta);
  }

as we cannot interact with private worker fields in the regular function.

Then the "low priority ring" turns into:

foo(...);
worker->lowPriorityRing = ring;

and loop body turns into

foo();
worker->dumpRings[ring_id] = ring;                                                                                                                                  
tag_to_id[tag] = ring_id;                                          
ring_id++;  

{
auto name = "r_lp_" + std::to_string(core_id);
auto offset = offsets[shm];
auto memaddr = (void*)((intptr_t)shm + offset);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid c-style casts.
It's generally better to avoid casts whatsoever, but I understand that some things cannot be done without them (though I'm pretty sure we can avoid some of them by using templates and/or std::variant, but that's a topic for discussion).

Here we should use named casts: auto memaddr = reinterpret_cast<void*>(reinterpret_cast<std::uintptr_t>(shm) + offset);

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use C-style typecast in sake of performance and the code is on our most important hot-path.

Also this memory region will contain many data structures (and arrays of them) mapped dynamically with data offsets. Another requirement that the region layout should be parseable by third-party application written in C or Go for example.

However, I think we could improve the approach but let us do this in the another piece of work.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, but I cannot resolve the conversation by myself, I guess I don't have the related permissions :)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unlike static_cast, but like const_cast, the reinterpret_cast expression does not compile to any CPU instructions (except when converting between integers and pointers, or between pointers on obscure architectures where pointer representation depends on its type). It is primarily a compile-time directive which instructs the compiler to treat expression as if it had the type target-type.

So there is no penalty in using reinterpret_cast. It also has a benefit of being easily greped

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants