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

Prototype JSON serializer for CallProfiler #323

Merged
merged 17 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from 7 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
126 changes: 126 additions & 0 deletions cpp/modmesh/toggle/RadixTree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,132 @@ void CallProfiler::print_profiling_result(const RadixTreeNode<CallerProfile> & n
}
}

void CallProfilerSerializer::serialize_call_profiler(const CallProfiler & profiler, std::ostream & outstream)
{
// Example:
Copy link
Member

Choose a reason for hiding this comment

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

We do not need to keep examples everywhere. The example in this block of comments seems to duplicate with that in google test. Please keep the code here clean by removing the unnecessary comments.

And marking only "Example" in this block does not help a maintainer to read. The only common information between the code and comment in the function is "radix_tree". It does not help maintainability.

If anything in the example comments here should be kept, please make it concise. And try to use doxygen format if it fits.

// {
// "radix_tree":
// {
// "nodes":[
// {"key":-1,"name":"","data":{"start_time": 0,"caller_name": "","total_time": 0,"call_count": 0,"is_running": 0},"children":[0]},
// {"key":0,"name":"void modmesh::detail::foo1()","data":{"start_time": 17745276708555250,"caller_name": "void modmesh::detail::foo1()","total_time": 61002916,"call_count": 1,"is_running": 1},"children":[1]},
// {"key":1,"name":"void modmesh::detail::foo2()","data":{"start_time": 17745276708555458,"caller_name": "void modmesh::detail::foo2()","total_time": 54002250,"call_count": 1,"is_running": 1},"children":[2]},
// {"key":2,"name":"void modmesh::detail::foo3()","data":{"start_time": 17745276743555833,"caller_name": "void modmesh::detail::foo3()","total_time": 19001833,"call_count": 1,"is_running": 1},"children":[]}
// ],
// "current_node":-1,
// "unique_id":3
// }
// }
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The json format is not informative enough.
Actually, the key is the ID of the function, and the same function may appear in the different trie nodes.
So I should add the address of the node in the nodes.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Additionally, the dictionary, that map the function to keyID, should be added into the radix tree.

Copy link
Member

@yungyuc yungyuc May 27, 2024

Choose a reason for hiding this comment

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

By the address of the node in the nodes, do you mean the address of the stack frame?

Maybe it is worth a try, but I am not 100% sure the stack frame address can be used to identify a node.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

By the address of the node in the nodes, do you mean the address of the stack frame?

Maybe it is worth a try, but I am not 100% sure the stack frame address can be used to identify a node.

Yes, it is.
I just record the relationship between nodes,
and I actually don't want to get the information from the real address.

By the way, I try to casting the pointer to the unsigned long when serializing.
It seems that we couldn't directly print the address in ubuntuOS.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

By the address of the node in the nodes, do you mean the address of the stack frame?
Maybe it is worth a try, but I am not 100% sure the stack frame address can be used to identify a node.

Yes, it is. I just record the relationship between nodes, and I actually don't want to get the information from the real address.

By the way, I try to casting the pointer to the unsigned long when serializing. It seems that we couldn't directly print the address in ubuntuOS.

You are right. Here is a bug.
https://github.com/solvcon/modmesh/actions/runs/9338060610/job/25700741584?pr=323
It seems that we couldn't identify a node by stack frame address because of the forbidden of the reinterpret_cast.
I think I should number the node by myself when Breadth-first searching.


outstream << R"({)";
outstream << R"("radix_tree": )";
CallProfilerSerializer::serialize_radix_tree(profiler, outstream);
outstream << R"(})";
}

void CallProfilerSerializer::serialize_radix_tree(const CallProfiler & profiler, std::ostream & outstream)
{
// Example:
Copy link
Member

Choose a reason for hiding this comment

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

This also looks like unnecessary and unclear comments.

// {
// "nodes":[
// {"key":-1,"name":"","data":{"start_time": 0,"caller_name": "","total_time": 0,"call_count": 0,"is_running": 0},"children":[0]},
// {"key":0,"name":"void modmesh::detail::foo1()","data":{"start_time": 17745276708555250,"caller_name": "void modmesh::detail::foo1()","total_time": 61002916,"call_count": 1,"is_running": 1},"children":[1]},
// {"key":1,"name":"void modmesh::detail::foo2()","data":{"start_time": 17745276708555458,"caller_name": "void modmesh::detail::foo2()","total_time": 54002250,"call_count": 1,"is_running": 1},"children":[2]},
// {"key":2,"name":"void modmesh::detail::foo3()","data":{"start_time": 17745276743555833,"caller_name": "void modmesh::detail::foo3()","total_time": 19001833,"call_count": 1,"is_running": 1},"children":[]}
// ],
// "current_node":-1,
// "unique_id":3
// }

outstream << R"({)";
Copy link
Collaborator

@tigercosmos tigercosmos Apr 29, 2024

Choose a reason for hiding this comment

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

I think you should not do the JSON serialization yourself. Consider using a library, such as RapidJson, to help you wrap the object into JSON format.

Here is what you can do:

  1. define a json schema
  2. implement the data structure in RadpidJson (or any other library)
  3. use the library to dump the json format

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think you should not do the JSON serialization yourself. Consider using a library, such as RapidJson, to help you wrap the object into JSON format.

Here is what you can do:

  1. define a json schema
  2. implement the data structure in RadpidJson (or any other library)
  3. use the library to dump the json format

Does it mean that I need to install RapidJson library in .github/workflows ?

Copy link
Collaborator

@tigercosmos tigercosmos Apr 29, 2024

Choose a reason for hiding this comment

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

you need to install RadpidJson in CMake, so you can use it in cpp files. (of course, also update the CI files)
You can do a study first before opting in RapidJson, perhaps there is a more suitable library for us.

Copy link
Member

Choose a reason for hiding this comment

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

I like @ThreeMonth03 's current approach.

Developing the JSON writing code provides more freedom than using a thirdparty. A thirdparty introduces additional dependency and increases the complexity of the building system. JSON is easy, and writing a parser should be fun.

I do not see a good reason to use a thirdparty JSON library.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Copy link
Collaborator

Choose a reason for hiding this comment

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

Per the discussion in Discord, I don't think we need a library for JSON, but if we need one, the current implementation is not general, we should have a JSON parser class instead.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Per the discussion in Discord, I don't think we need a library for JSON, but if we need one, the current implementation is not general, we should have a JSON parser class instead.

Does it mean that I should survey and implement a general json parser class?

outstream << R"("nodes": [)";
CallProfilerSerializer::serialize_radix_tree_nodes(profiler.radix_tree().get_current_node(), outstream);
outstream << R"(],)";
outstream << R"("current_node": )" << profiler.radix_tree().get_current_node()->key() << R"(,)";
outstream << R"("unique_id": )" << profiler.radix_tree().get_unique_node();
outstream << R"(})";
}
void CallProfilerSerializer::serialize_radix_tree_nodes(const RadixTreeNode<CallerProfile> * node, std::ostream & outstream)
Copy link
Member

Choose a reason for hiding this comment

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

Keep a blank line between functions.

Is it possible to make clang-format capture this? (Apparently we haven't configured it this way, yet.)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

No, I use the clang-format tools, and it doesn't work.

{
std::queue<const RadixTreeNode<CallerProfile> *> nodes_buffer;
nodes_buffer.push(node);
bool is_first_node = true;

// Serialize the nodes in a breadth-first manner.
Copy link
Member

Choose a reason for hiding this comment

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

Good comment. It's informative and helps read the code.

while (!nodes_buffer.empty())
{
const int nodes_buffer_size = nodes_buffer.size();
for (int i = 0; i < nodes_buffer_size; i++)
Copy link
Member

Choose a reason for hiding this comment

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

Use ++i for clearer semantics. Both ++i and i++ generates the same instructions in this construct, but the semantics differ. We want the former, not the latter.

If i is not a fundamental types, i++ could have unwanted side effects.

{
const RadixTreeNode<CallerProfile> * current_node = nodes_buffer.front();
nodes_buffer.pop();
CallProfilerSerializer::serialize_radix_tree_node(*current_node, is_first_node, outstream);
is_first_node = false;
for (const auto & child : current_node->children())
{
nodes_buffer.push(child.get());
}
}
}
}

void CallProfilerSerializer::serialize_radix_tree_node(const RadixTreeNode<CallerProfile> & node, bool is_first_node, std::ostream & outstream)
{
// Example:
Copy link
Member

Choose a reason for hiding this comment

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

This small example is informative, but the purpose is not clearly written in the comment. "Example" alone does not help. Please come up with clearer description for what you want to say to a maintainer (assuming they are not you).

// {
// "key":-1,
// "name":"",
// "data":{"start_time": 0,"caller_name": "","total_time": 0,"call_count": 0,"is_running": 0},
// "children":[0]
// }

// Avoid the trailing comma.
if (!is_first_node)
{
outstream << R"(,)";
}
outstream << R"({)";
outstream << R"("key": )" << node.key() << R"(,)";
outstream << R"("name": ")" << node.name() << R"(",)";
outstream << R"("data": )";
CallProfilerSerializer::serialize_caller_profile(node.data(), outstream);
outstream << R"(,)";
outstream << R"("children": [)";
bool is_first_child = true;
for (const auto & child : node.children())
{
// Avoid the trailing comma.
if (!is_first_child)
{
outstream << R"(,)";
}
is_first_child = false;
outstream << child->key();
}
outstream << R"(])";
outstream << R"(})";
}

void CallProfilerSerializer::serialize_caller_profile(const CallerProfile & profile, std::ostream & outstream)
{
// Example:
Copy link
Member

Choose a reason for hiding this comment

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

Make it clearer.

// {
// "start_time": 0,
// "caller_name": "",
// "total_time": 0,
// "call_count": 0,
// "is_running": 0
// }

outstream << R"({)";
outstream << R"("start_time": )" << profile.start_time.time_since_epoch().count() << R"(,)";
outstream << R"("caller_name": ")" << profile.caller_name << R"(",)";
outstream << R"("total_time": )" << profile.total_time.count() << R"(,)";
outstream << R"("call_count": )" << profile.call_count << R"(,)";
outstream << R"("is_running": )" << profile.is_running;
outstream << R"(})";
}

} /* end namespace modmesh */
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I add the comment about the serialization format.
Furthermore, I traverse the radix tree by bfs with a queue.

Copy link
Member

Choose a reason for hiding this comment

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

It's good to use a loop to traverse. Is there a performance concern?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I have no idea. It seems to be fine.
The argument are constant referenced.
And there is not any std::flush that may affect the performance.


// vim: set ff=unix fenc=utf8 et sw=4 ts=4 sts=4:
48 changes: 48 additions & 0 deletions cpp/modmesh/toggle/RadixTree.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include <sstream>
#include <stack>
#include <unordered_map>
#include <queue>

namespace modmesh
{
Expand Down Expand Up @@ -191,6 +192,34 @@ struct CallerProfile
call_count++;
}

// It deserialize the json format.
Copy link
Member

Choose a reason for hiding this comment

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

This comment block is unnecessary.

/*
void deserialize(const std::string & json)
{
std::stringstream ss(json);
std::string info;
// start_time
std::getline(ss, info, ':');
std::getline(ss, info, ',');
start_time = std::chrono::high_resolution_clock::time_point(std::chrono::nanoseconds(std::stoll(info)));
// caller_name
std::getline(ss, info, ':');
std::getline(ss, info, ',');
caller_name = info;
// total_time
std::getline(ss, info, ':');
std::getline(ss, info, ',');
total_time = std::chrono::nanoseconds(std::stoll(info));
// call_count
std::getline(ss, info, ':');
std::getline(ss, info, ',');
call_count = std::stoi(info);
// is_running
std::getline(ss, info, ':');
std::getline(ss, info, ',');
is_running = std::stoi(info);
}
*/
std::chrono::high_resolution_clock::time_point start_time;
std::string caller_name;
std::chrono::nanoseconds total_time = std::chrono::nanoseconds(0); /// use nanoseconds to have higher precision
Expand Down Expand Up @@ -261,6 +290,8 @@ class CallProfiler
reset();
}

const RadixTree<CallerProfile> & radix_tree() const { return m_radix_tree; }

private:
void print_profiling_result(const RadixTreeNode<CallerProfile> & node, const int depth, std::ostream & outstream) const;

Expand Down Expand Up @@ -310,6 +341,23 @@ class CallProfilerProbe
CallProfiler & m_profiler;
}; /* end struct CallProfilerProbe */

class CallProfilerSerializer
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I create CallProfilerSerializer and move the serialization function in to the CallProfilerSerializer.

Copy link
Member

Choose a reason for hiding this comment

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

You should add some comment for the class CallProfilerSerializer. It may be good to point to the google test file.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'm not sure whether the comment is enough to help reading.

{
public:
// It returns the json format of the CallProfiler.
static void serialize(const CallProfiler & profiler, std::ostream & outstream)
{
serialize_call_profiler(profiler, outstream);
}

private:
static void serialize_call_profiler(const CallProfiler & profiler, std::ostream & outstream);
static void serialize_radix_tree(const CallProfiler & profiler, std::ostream & outstream);
static void serialize_radix_tree_nodes(const RadixTreeNode<CallerProfile> * node, std::ostream & outstream);
static void serialize_radix_tree_node(const RadixTreeNode<CallerProfile> & node, bool is_first_node, std::ostream & outstream);
static void serialize_caller_profile(const CallerProfile & profile, std::ostream & outstream);
}; /* end struct CallProfilerSerializer */

#ifdef CALLPROFILER

#ifdef _MSC_VER
Expand Down
83 changes: 82 additions & 1 deletion gtests/test_nopython_callprofiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,5 +212,86 @@ TEST_F(CallProfilerTest, cancel)
EXPECT_EQ(radix_tree().get_unique_node(), 0);
}

#ifdef _MSC_VER
std::string serializeExample = R"x({"radix_tree": {"nodes": [{"key": -1,"name": "","data": {"start_time": 0,"caller_name": "","total_time": 0,"call_count": 0,"is_running": 0},"children": [0]},{"key": 0,"name": "void __cdecl modmesh::detail::foo1(void)","data": {"start_time": 18348582416327166,"caller_name": "void __cdecl modmesh::detail::foo1(void)","total_time": 61001042,"call_count": 1,"is_running": 1},"children": [1]},{"key": 1,"name": "void __cdecl modmesh::detail::foo2(void)","data": {"start_time": 18348582416327416,"caller_name": "void __cdecl modmesh::detail::foo2(void)","total_time": 54000667,"call_count": 1,"is_running": 1},"children": [2]},{"key": 2,"name": "void __cdecl modmesh::detail::foo3(void)","data": {"start_time": 18348582451327708,"caller_name": "void __cdecl modmesh::detail::foo3(void)","total_time": 19000167,"call_count": 1,"is_running": 1},"children": []}],"current_node": -1,"unique_id": 3}})x";
Copy link
Member

Choose a reason for hiding this comment

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

The line (and that in the else fence) is too long! Please do not use more than 100 characters in a line for the fixture. And please use indentation when breaking the line.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I will fix them after I write the gtest.

#else
std::string serializeExample = R"x({"radix_tree": {"nodes": [{"key": -1,"name": "","data": {"start_time": 0,"caller_name": "","total_time": 0,"call_count": 0,"is_running": 0},"children": [0]},{"key": 0,"name": "void modmesh::detail::foo1()","data": {"start_time": 18348582416327166,"caller_name": "void modmesh::detail::foo1()","total_time": 61001042,"call_count": 1,"is_running": 1},"children": [1]},{"key": 1,"name": "void modmesh::detail::foo2()","data": {"start_time": 18348582416327416,"caller_name": "void modmesh::detail::foo2()","total_time": 54000667,"call_count": 1,"is_running": 1},"children": [2]},{"key": 2,"name": "void modmesh::detail::foo3()","data": {"start_time": 18348582451327708,"caller_name": "void modmesh::detail::foo3()","total_time": 19000167,"call_count": 1,"is_running": 1},"children": []}],"current_node": -1,"unique_id": 3}})x";
#endif

std::string start_time_str = R"("start_time": )";
std::string total_time_str = R"("total_time": )";
std::string caller_name_str = R"(,"caller_name": )";
std::string call_count_str = R"(,"call_count": )";

TEST_F(CallProfilerTest, test_serialization)
{
pProfiler->reset();

foo1();

// Example:
Copy link
Member

Choose a reason for hiding this comment

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

Could you please use a fixture (which can be just a string in this test file) to compare with the serialization results?

Copy link
Member

Choose a reason for hiding this comment

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

Does this example comment block have the same content as your fixture string? If yes, this comment block should be removed. And as mentioned above, the fixture strings should use good indentation.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, it is.
I will remove this comment block.

// {
// "radix_tree":
// {
// "nodes":[
// {"key":-1,"name":"","data":{"start_time": 0,"caller_name": "","total_time": 0,"call_count": 0,"is_running": 0},"children":[0]},
// {"key":0,"name":"void modmesh::detail::foo1()","data":{"start_time": 17745276708555250,"caller_name": "void modmesh::detail::foo1()","total_time": 61002916,"call_count": 1,"is_running": 1},"children":[1]},
// {"key":1,"name":"void modmesh::detail::foo2()","data":{"start_time": 17745276708555458,"caller_name": "void modmesh::detail::foo2()","total_time": 54002250,"call_count": 1,"is_running": 1},"children":[2]},
// {"key":2,"name":"void modmesh::detail::foo3()","data":{"start_time": 17745276743555833,"caller_name": "void modmesh::detail::foo3()","total_time": 19001833,"call_count": 1,"is_running": 1},"children":[]}
// ],
// "current_node":-1,
// "unique_id":3
// }
// }

std::stringstream ss;
CallProfilerSerializer::serialize(*pProfiler, ss);

int ss_start_time_pos0 = ss.str().find(start_time_str);
Copy link
Member

Choose a reason for hiding this comment

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

Why do you need to do string search yourself? They look too convoluted to be useful tests. Could you please explain what you are doing here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The theory output is not always same as the fixture string.
The fixture string contains the information of the start_time and total_time of the program.
Thus, I only compare the string that doesn't include time information.

int ss_start_time_pos1 = ss.str().find(start_time_str, ss_start_time_pos0 + 1);
int ss_start_time_pos2 = ss.str().find(start_time_str, ss_start_time_pos1 + 1);
int ss_start_time_pos3 = ss.str().find(start_time_str, ss_start_time_pos2 + 1);
int ss_total_time_pos0 = ss.str().find(total_time_str);
int ss_total_time_pos1 = ss.str().find(total_time_str, ss_total_time_pos0 + 1);
int ss_total_time_pos2 = ss.str().find(total_time_str, ss_total_time_pos1 + 1);
int ss_total_time_pos3 = ss.str().find(total_time_str, ss_total_time_pos2 + 1);
int ss_caller_name_pos0 = ss.str().find(caller_name_str);
int ss_caller_name_pos1 = ss.str().find(caller_name_str, ss_caller_name_pos0 + 1);
int ss_caller_name_pos2 = ss.str().find(caller_name_str, ss_caller_name_pos1 + 1);
int ss_caller_name_pos3 = ss.str().find(caller_name_str, ss_caller_name_pos2 + 1);
int ss_call_count_pos0 = ss.str().find(call_count_str);
int ss_call_count_pos1 = ss.str().find(call_count_str, ss_call_count_pos0 + 1);
int ss_call_count_pos2 = ss.str().find(call_count_str, ss_call_count_pos1 + 1);
int ss_call_count_pos3 = ss.str().find(call_count_str, ss_call_count_pos2 + 1);

int example_start_time_pos0 = serializeExample.find(start_time_str);
int example_start_time_pos1 = serializeExample.find(start_time_str, example_start_time_pos0 + 1);
int example_start_time_pos2 = serializeExample.find(start_time_str, example_start_time_pos1 + 1);
int example_start_time_pos3 = serializeExample.find(start_time_str, example_start_time_pos2 + 1);
int example_total_time_pos0 = serializeExample.find(total_time_str);
int example_total_time_pos1 = serializeExample.find(total_time_str, example_total_time_pos0 + 1);
int example_total_time_pos2 = serializeExample.find(total_time_str, example_total_time_pos1 + 1);
int example_total_time_pos3 = serializeExample.find(total_time_str, example_total_time_pos2 + 1);
int example_caller_name_pos0 = serializeExample.find(caller_name_str);
int example_caller_name_pos1 = serializeExample.find(caller_name_str, example_caller_name_pos0 + 1);
int example_caller_name_pos2 = serializeExample.find(caller_name_str, example_caller_name_pos1 + 1);
int example_caller_name_pos3 = serializeExample.find(caller_name_str, example_caller_name_pos2 + 1);
int example_call_count_pos0 = serializeExample.find(call_count_str);
int example_call_count_pos1 = serializeExample.find(call_count_str, example_call_count_pos0 + 1);
int example_call_count_pos2 = serializeExample.find(call_count_str, example_call_count_pos1 + 1);
int example_call_count_pos3 = serializeExample.find(call_count_str, example_call_count_pos2 + 1);

// Validate the serialization result except for the start_time and total_time
EXPECT_EQ(ss.str().substr(0, ss_start_time_pos0 + start_time_str.size()), serializeExample.substr(0, example_start_time_pos0 + start_time_str.size()));
EXPECT_EQ(ss.str().substr(ss_caller_name_pos0, ss_total_time_pos0 + total_time_str.size() - ss_caller_name_pos0), serializeExample.substr(example_caller_name_pos0, example_total_time_pos0 + total_time_str.size() - example_caller_name_pos0));
EXPECT_EQ(ss.str().substr(ss_call_count_pos0, ss_start_time_pos1 - ss_call_count_pos0), serializeExample.substr(example_call_count_pos0, example_start_time_pos1 - example_call_count_pos0));
EXPECT_EQ(ss.str().substr(ss_caller_name_pos1, ss_total_time_pos1 + total_time_str.size() - ss_caller_name_pos1), serializeExample.substr(example_caller_name_pos1, example_total_time_pos1 + total_time_str.size() - example_caller_name_pos1));
EXPECT_EQ(ss.str().substr(ss_call_count_pos1, ss_start_time_pos2 - ss_call_count_pos1), serializeExample.substr(example_call_count_pos1, example_start_time_pos2 - example_call_count_pos1));
EXPECT_EQ(ss.str().substr(ss_caller_name_pos2, ss_total_time_pos2 + total_time_str.size() - ss_caller_name_pos2), serializeExample.substr(example_caller_name_pos2, example_total_time_pos2 + total_time_str.size() - example_caller_name_pos2));
EXPECT_EQ(ss.str().substr(ss_call_count_pos2, ss_start_time_pos3 - ss_call_count_pos2), serializeExample.substr(example_call_count_pos2, example_start_time_pos3 - example_call_count_pos2));
EXPECT_EQ(ss.str().substr(ss_caller_name_pos3, ss_total_time_pos3 + total_time_str.size() - ss_caller_name_pos3), serializeExample.substr(example_caller_name_pos3, example_total_time_pos3 + total_time_str.size() - example_caller_name_pos3));
EXPECT_EQ(ss.str().substr(ss_call_count_pos3), serializeExample.substr(example_call_count_pos3));
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Here is the test of the serialization function.
I check the output except for the start time and the total time of the functions.


} // namespace detail
} // namespace modmesh
} // namespace modmesh
Loading