-
Notifications
You must be signed in to change notification settings - Fork 264
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
Added sample interator api #191
Conversation
@@ -4309,22 +4309,12 @@ static void Server_Update(Server* server) | |||
|
|||
#define SAMPLE_NAME_LEN 128 | |||
|
|||
typedef enum SampleType |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved to the header, and renamed to rmtSampleType
lib/Remotery.c
Outdated
if (g_Settings.sampletree_handler != NULL) | ||
{ | ||
g_Settings.sampletree_handler(rmt, g_Settings.sampletree_context, sample_tree); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had to put it before the FreeSamples()
as the sample pointers would be invalid after that call.
lib/Remotery.c
Outdated
RMT_API rmtSampleIterator _rmt_IterateChildren(rmtSample* sample) | ||
{ | ||
rmtSampleIterator iterator; | ||
iterator.sample = 0; | ||
iterator.initial = sample != NULL ? sample->first_child : 0; | ||
return iterator; | ||
} | ||
|
||
RMT_API rmtBool _rmt_IterateNext(rmtSampleIterator* iter) | ||
{ | ||
if (iter->initial != NULL) | ||
{ | ||
iter->sample = iter->initial; | ||
iter->initial = 0; | ||
} | ||
else | ||
{ | ||
if (iter->sample != NULL) | ||
iter->sample = iter->sample->next_sibling; | ||
} | ||
|
||
return iter->sample != NULL ? RMT_TRUE : RMT_FALSE; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Following the pattern from this gist:
https://gist.github.com/pervognsen/744066869da509a15c4e08fc9408207e
lib/Remotery.c
Outdated
RMT_API const char* _rmt_SampleTreeGetThreadName(rmtMsgSampleTree* sample_tree) | ||
{ | ||
return sample_tree->threadName; | ||
} | ||
|
||
RMT_API rmtSample* _rmt_SampleTreeGetRootSample(rmtMsgSampleTree* sample_tree) | ||
{ | ||
return sample_tree->rootSample; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At first, I passed the threadName
explicitly to the callback function, but later thought that passing the opaque message pointer fits the api a bit better:
- Easier to add more accessor functions later
- Matches the Sample accessor api used in the callback api
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm... yes... that's a good counter argument. I'll edit my comment.
lib/Remotery.c
Outdated
RMT_API const char* _rmt_SampleGetName(Remotery* rmt, rmtSample* sample) | ||
{ | ||
const char* name = StringTable_Find(rmt->string_table, sample->name_hash); | ||
if (name == NULL) | ||
{ | ||
return "null"; | ||
} | ||
return name; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs the Remotery pointer, so I explicitly pass that in the callback.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should use g_Remotery
in the implementation instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking that too, but I was perhaps trying to remove the need to use a global variable.
The current setup in the PR was to address the initialization problem:
The problem with the user context and the remotery pointer is a catch 22:
// Setting up settings before creating the context
Remotery *rmt;
rmtSettings* settings = rmt_Settings();
settings->sampletree_handler = dumpTree;
settings->sampletree_context = rmt; // Not valid yet
rmt_CreateGlobalInstance(&rmt);
An alternative, albeit not very clean code flow either:
// Setup some setting variables before creating the Remotery instance...
Remotery *rmt;
rmtSettings* settings = rmt_Settings();
settings->port = port;
rmt_CreateGlobalInstance(&rmt);
// ... and set some settings after
settings->sampletree_handler = dumpTree;
settings->sampletree_context = rmt; // Not valid yet
But, I have no examples of other users use case, and they can for sure create their own custom contexts etc.
So I'll go ahead with removing the Remotery pointer from the callback function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most of the internal code uses the global variable g_Remotery
. The API explicitly avoids requesting it from the user. It even has a DLL API to cater for this where the use calls rmt_SetGlobalInstance
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, now I finally see what you mean. Fixing...
RMT_SampleType_OpenGL, | ||
RMT_SampleType_Metal, | ||
RMT_SampleType_Count, | ||
} rmtSampleType; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given the other public interfaces in the header, I prefixed it with RMT_.
Might want to be upper case, to match style of rmtError
enum?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is fine. I wanted to remove all error-messages-as-enums, anyway and replace them with 4 or 5 broader error enums that give you optional message retrieval.
lib/Remotery.h
Outdated
@@ -363,6 +388,7 @@ typedef void* (*rmtMallocPtr)(void* mm_context, rmtU32 size); | |||
typedef void* (*rmtReallocPtr)(void* mm_context, void* ptr, rmtU32 size); | |||
typedef void (*rmtFreePtr)(void* mm_context, void* ptr); | |||
typedef void (*rmtInputHandlerPtr)(const char* text, void* context); | |||
typedef void (*rmtSampleTreeHandlerPtr)(Remotery* rmt, void* cbk_context, rmtMsgSampleTree* sample_tree); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The callback type and its arguments.
RMT_API rmtU64 _rmt_SampleGetTime(rmtSample* sample); | ||
RMT_API rmtU64 _rmt_SampleGetSelfTime(rmtSample* sample); | ||
RMT_API void _rmt_SampleGetColour(rmtSample* sample, rmtU8* r, rmtU8* g, rmtU8* b); | ||
RMT_API rmtSampleType _rmt_SampleGetType(rmtSample* sample); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently, they all are "private", with the "_" prefix.
I guess they should also be wrapped with the "RMT_OPTIONAL" define.
Should it also be contained withing a new tag, e.g. RMT_ENABLED_ITERATORS
? Might be a bit overkill?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't worry about adding a RMT_ENABLED_ITERATORS
- just RMT_ENABLED
will do.
sample/dump.c
Outdated
void dumpTree(Remotery* rmt, void* ctx, rmtMsgSampleTree* sample_tree) | ||
{ | ||
rmtSample* root = _rmt_SampleTreeGetRootSample(sample_tree); | ||
const char* thread_name = _rmt_SampleTreeGetThreadName(sample_tree); | ||
|
||
printf("// ******************** DUMP TREE: %s ************************\n", thread_name); | ||
|
||
printTree(rmt, root, 0); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Example callback
sample/dump.c
Outdated
void printTree(Remotery* rmt, rmtSample* sample, int indent) | ||
{ | ||
printSample(rmt, sample, indent); | ||
|
||
rmtSampleIterator iter = _rmt_IterateChildren(sample); | ||
while (_rmt_IterateNext(&iter)) { | ||
printTree(rmt, iter.sample, indent+1); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Example of iterator
Really great stuff. I started reviewing this before you left your comments so I'll address them now. |
lib/Remotery.c
Outdated
@@ -6115,6 +6105,11 @@ static rmtError Remotery_SendSampleTreeMessage(Remotery* rmt, Message* message) | |||
error = bin_SampleTree(bin_buf, sample_tree); | |||
rmt_EndCPUSample(); | |||
|
|||
if (g_Settings.sampletree_handler != NULL) | |||
{ | |||
g_Settings.sampletree_handler(rmt, g_Settings.sampletree_context, sample_tree); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than passing sample_tree
and having to create the opaque type rmtMsgSampleTree
, can you pass sample_tree->rootSample
instead? Then you only need to expose the rmtSample
type to the public API.
There is also then no need for _rmt_SampleTreeGetRootSample
and _rmt_SampleTreeGetThreadName
can be replaced with passing the thread name to your sampletree_handler
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leave as is but could you rename to rmtSampleTree
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure!
lib/Remotery.h
Outdated
RMT_API rmtSample* _rmt_SampleTreeGetRootSample(rmtMsgSampleTree* sample_tree); | ||
|
||
// Sample accessors | ||
RMT_API const char* _rmt_SampleGetName(Remotery* rmt, rmtSample* sample); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need a comment that accessing all this data should only be done from the callback and not another thread elsewhere. This is because functions like _rmt_SampleGetName
use StringTable_Find
which is currently only safe to access from the main Remotery thread.
@@ -661,6 +691,23 @@ RMT_API void _rmt_BeginMetalSample(rmtPStr name, rmtU32* hash_cache); | |||
RMT_API void _rmt_EndMetalSample(void); | |||
#endif | |||
|
|||
// Iterator |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this API compile and link when RMT_ENABLED=0
? Prefix-underscores shouldn't be used here.
As an example:
RMT_API void _rmt_LogText(rmtPStr text);
This is the function signature that is part of the Private interface and this is the macro which gets compiled-out when RMT_ENABLED=0
:
#define rmt_LogText(text) \
RMT_OPTIONAL(RMT_ENABLED, _rmt_LogText(text))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have now added this, but I'm wondering if the use case is a bit different.
The client code will fail to compile on code like this if we simply omit the info:
error: expected expression
const char* name = rmt_SampleGetName(ctx->rmt, sample);
I see two options:
- Each such interface needs to produce "valid" values, which is counter intuitive when using the
RMT_OPTIONAL + RMT_ENABLED
- Letting the client control their code using
#ifdef RMT_ENABLED
explicitly around this particular piece of code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, there's going to be a lot of errors if you implement some of them in terms of RMT_OPTIONAL
as they need to return a value even when RMT_ENABLED=0
.
One option is to return nothing and specify the output as an address parameter to the function call but that would then prevent you from initialising at the declaration point in C when multiple calls are involved.
Have you looked at using RMT_OPTIONAL_RET
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I updated the api now to use the RMT_OPTIONAL+RMT_OPTIONAL_RET and the dump.c example builds and runs in -DRMT_ENABLED=0
as well.
lib/Remotery.c
Outdated
RMT_API const char* _rmt_SampleTreeGetThreadName(rmtMsgSampleTree* sample_tree) | ||
{ | ||
return sample_tree->threadName; | ||
} | ||
|
||
RMT_API rmtSample* _rmt_SampleTreeGetRootSample(rmtMsgSampleTree* sample_tree) | ||
{ | ||
return sample_tree->rootSample; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm... yes... that's a good counter argument. I'll edit my comment.
Renamed to rmtSampleTree Added RMT_OPTIONAL functions for the iterator/sample api
Tweaked api for the iterator to make it work better with c89 and the RMT_OPTIONAL
#define rmt_IterateChildren(iter, sample) \ | ||
RMT_OPTIONAL(RMT_ENABLED, _rmt_IterateChildren(iter, sample)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tweaked the api from
rmtSampleIterator iter = rmt_IterateChildren(sample);
to
rmtSampleIterator iter;
rmt_IterateChildren(&iter, sample);
in order to both make it more C89 compatible, and also make it work with RMT_OPTIONAL better.
I love this... going to get some tea and make sure I understand the implications of adding this before merge. Thanks so much. |
Fixes #190