-
Notifications
You must be signed in to change notification settings - Fork 50
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
tracing and profiling interface and basic backends #672
Conversation
Did you withhold the src/common/libutil/profiling.[ch] files for some reason? |
Thanks for the heads up don. Rebase was giving me fits and something must have gone wrong. I'll add them back in shortly. From: Don Lipari Did you withhold the src/common/libutil/profiling.[ch] files for some reason? — |
@lipari: the files are in now. I'm re-working how exactly caliper records information so it's a bit easier to parse, but the interface is unlikely to shift much. One heads up though, don't compile the caliper library and flux with one of the dotkit gccs and try to use it on hype, the compute nodes don't have the appropriate libstdc++, so you'll get cryptic link errors... @dongahn, is there someone to report this kind of thing to? I keep ending up fighting our compilers all over the place. |
@trws: I would start from John Gyllenhaal. |
@garlick, @grondo: This has had all TAU foolishness removed, been cleaned up somewhat, and rebased to current master. There is something causing an event to be recorded multiple times, but it appears to be a caliper bug that I'm following up on (and it's easy to filter off events that have identical record, times, etc.). Currently it tracks the rank, thread id, thread type (main or module thread), module name if present, message type and message topic for handle callbacks, and times all such message handlers. If you want to give it a try, just use --enable-caliper and give the library and include paths for a copy of caliper, then run flux with The one other noticeable downside right now, that I would love some thoughts on if something comes to mind, is that flux/wreck processes under the brokers end up emitting profiles as well. I haven't found a good way to turn off caliper at that boundary yet, but it should be reasonably possible with some environment filtering or similar. |
Great, thanks! It's easier to grok this PR as a single diff - might want to squash it down, and if there's any detritus remaining from tau (xmalloc? static htab decl. in wrexec), drop it. Is the global state essential to communicating with caliper, or could it be moved to If we're making caliper the "native" trace format, can the indirection through profiling.h be dropped? I will get caliper built and play with it a bit and probably then all will become clear. Thanks again for getting this all going. |
Is there a reason both |
Completely agree @garlick, I have every intention of squashing it before merge, but there are some things from the history that I may want to put in a future PR ( I had part of a compiler auto-instrument hook in there ) to pull out first. The global state can be somewhere else, but all they are is named event types. They should be common to the whole process, and there should only ever be one copy of those variables. I have no issue with moving them if you prefer, but there should never be more than one of each (or we may get multiple attributes with the same name and type, which would be confusing). I can certainly remove the header, but I wasn't sure whether to do it or not. The header allows the common calls to be compiled out without too many guards, but it's no more than a convenience. If they're both still there, it's by mistake, the Clearly this need further cleanup, so I'll get to that shortly and post an update. |
No rush! I've got caliper built on my desktop and I'll figure out how to get some trace output tomorrow. |
If you unset caliper environment variables in the initial program shell does that fix a large part of the problem? For |
One more (probably very naive) question. In @tpatki's work with tracing in the scheduler we had the idea to start tracing with an event or other request, allowing tracing to be started/stopped dynamically. Would this ever be possible with caliper? (Doesn't need to be now, but dynamic tracing would be extremely handy in the future) |
Unsettling the end really doesn't do it because of they way the wreck processes are forked. This might be part of choosing when we do and don't want tracing to happen. It's definitely possible to do targeted tracing with caliper, but I haven't worked out the best way to manage that yet. It has built in support for some kinds of filtering and white/blacklisting, but we probably want our own event classes or regions to make that reasonably usable. From: Mark Grondona One more (probably very naive) question. In @tpatkihttps://github.com/tpatki's work with tracing in the scheduler we had the idea to start tracing with an event or other request, allowing tracing to be started/stopped dynamically. Would this ever be possible with caliper? (Doesn't need to be now, but dynamic tracing would be extremely handy in the future) — |
Sorry I'm being dense but I don't follow that, I'm not sure of how wreck processes are forked in any special way, but this would be easy to change if it helps here, and is good feedback for the replacement.
Yeah, I was thinking the same thing, if we had our own filters, possibly dynamic like linux ftrace, that would be extremely handy. However, I looked at how ftrace accomplishes near zero overhead when tracing is disabled and it is suitably tricky that I don't think it is something we'd attempt. I was hoping we'd be able to hide any complexity behind a |
You could push a copy of this branch first
Then go ahead and modify the PR branch as needed and |
Incidentally, d193241 is a simplified version of your pr
Didn't mean to gut your abstractions but I found this a bit easier to map directly to the caliper documentation for starting out. Feel free to ignore. |
I didn't get very far yesterday with some interruptions, but did have this thought (and started writing some code for it though not there yet): it seems that caliper gets initialized and produces a zero length output file for an executable linked to it, even if no caliper calls are made. To get control of this, it seems like caliper should only be linked to executables that require tracing, for starters the broker. To get trace calls added to the dispatcher without linking caliper to libflux.so, perhaps we could implement a trace registration interface that registers begin/end callbacks for specific topic strings or f Any feelings about this approach? Can we come up with a generic typedef void (*flux_trace_f)(const char *name, void *arg); (In the dispatcher I would construct |
Could we also push a patch to caliper that opens output files dynamically, and only when there is data to write? I like your callback idea. I'd really like to see the ability to have tracing enabled by default in the build with a However, if I'm the only one asking for this feel free to ignore me. |
@grondo, as to the patch, it wouldn't be a bad thing to have a caliper plugin that does something more sensible for flux in general for sure. The specific avoid opening until there's output patch that is something I imagine @daboehme would take if someone wants to make the adjustment. As to using callbacks for tracing, I'm generally for having some of those mechanisms, especially since that's how compiler-instrumentation works at runtime it's good to have a way to tie into that. That said, it means we have to build rather more on a per-trace-target basis than we would otherwise, and every call into it will be a bit more expensive. Either way, having a way to filter what does and doesn't get logged is going to be important, so the code for selecting a pattern or set of specs would be useful regardless. I have an appointment set up with @daboehme to talk about how to use caliper with flux, and how to use the built-in filtering stuff, this Friday if anyone is interested in joining in. I want to have a better handle on that before building too much abstraction that might be duplicative. Speaking of, I think you're right @garlick that it's best to drop the profiling.h header, at least until we have a generic interface or something we want to use, with TAU gone there's no reason for it, so I'll probably merge your commit and add some of the adjustments I've been working on to that. |
Just a clarification: I think we get empty caliper logs only if we set the CALI_CONFIG_PROFILE environment variable. If that's set (e.g. inherited by wrexecd) then we get a log file per process. That seemed odd to me because wrexecd didn't call cali_* at all internally, but I could see the argument for it: if you enable tracing and none of the trace points happen to be executed, that's a valid trace result. So maybe not a bug? |
That seems more reasonable to me. |
dlopening libcaliper might be a way to enable Flux to be built with tracing that is enabled at runtime, and to avoiding getting trace files where they are not wanted. There is not much in the C API to make accessing it via dlsym super incovenient. |
Should I move the flux-sched tracing to caliper as well? @dongahn wanted a simpler tracing mechanism (what I was working on earlier) but caliper was Martin/my original suggestion too. What do you all think? |
Sounds good to me. |
I like @garlick's idea -- it would be interesting to see if there is a measurable performance overhead using this approach. @tpatki, it would be cool if sched tracing uses a similar scheme @garlick is working toward, then all flux tracing would come out in a similar format to the same files. That would be cool. We still might want some scheme for filtering which tracepoints get enabled |
Well, I think we are headed towards a generic trace framework provided by core, but it wouldn't hurt for you to switch over to caliper if you don't mind switching again once we have sorted out the generic hooks. At least that's what I was thinking. @trws should chime in with hits thoughts - I hope he doesn't feel I've hijacked his PR :-) |
@daboehme, I've put in some time looking for the invalid node record issue. It's definitely related to using the C interface snapshot function, in that I get one invalid node record for each element I place in the snapshot, once per run. The data being snapshotted appears to be correct, but I still get the invalid node with no data and a UINT64_MAX attr. Any thoughts? |
configure --enable-caliper to build flux with profiling
Ok, I think this last push addresses the remaining issues. The invalid nodes were being created because the profiling call was being invoked inside of connector_init by messaging happening after it initialized its part of the handle but before letting the handle finish initializing itself. Also rebased and squashed down. |
Thanks! I'll take a look asap, hopefully by early tomorrow. |
@trws, I sanity checked this PR and it all looks pretty good! Some minor comments:
|
I did, or at least thought I did, address @garlick's comment about the flags, and rewording the commit message is no problem. As to the logging, there's actually a bit of a choice there. I can actually build flux so that it builds against the stubs library, then use LD_PRELOAD to load in caliper when we actually want results. Alternately, we can control the logging and other things, but having it use the stubs by default should fix all of the testing issues, and make a build with caliper built in run faster when caliper's real implementation isn't loaded. What do you think would make more sense there? Either is equally easy honestly. |
Ok, thanks, sorry I missed your changes related to @garlick's comment! For the Caliper logging issue, I guess it is a matter of taste, but my personal preference is that libraries do not log to stderr by default for informational messages like "hello" and "goodbye" ;-) Even when I'm using Caliper purposely to trace a 100 broker job, I'm probably not going to want to see 100 "Initialized" messages on stderr I guess is my point. The dlopen idea sounds great to me! Perhaps as a follow on to this PR? If you fix up the commit message I'd be willing to merge this PR as is so that you aren't required to continually rebase on master (and it will be nice to have some kind of canned tracing support in the next flux-core tag) Thanks! |
I completely agree with that sentiment for what it's worth... @daboehme, any chance of a default change on that at some point? For now, we can manipulate the environment variables or something, but for a library we want to keep loaded I'm not sure it's a good thing. Let me take a minute to see if I can do the switch to stubs easily, failing that we'll make that part of another pr. |
This update adds tracing for various properties of messages, RPCs, events, etc. This will not give us all we need to get matches for all messages, but it's on the way. Caliper is currently pulled in using pkg-config to configure our build, if that becomes annoying we may want to rework that at some point. As an FYI, be aware that the profiling_msg_snapshot routine can be called due to messaging activity inside connector_init, so the profiling object is not ready, and potentially cause uninitialized nodes to be emitted. This is currently addressed by a check and return in the snapshot routine, but if at some point those code-paths become threaded something fancier may be required.
Flux now links to the stubs by default, and no longer has references to the pkg-config variables outside of the configuration script. In order to use the tracing, build as before and LD_PRELOAD libcaliper.so, with that it will work as normal, otherwise all of the calls are stubbed out.
I poked at this Friday and over the weekend a bit. The stubs seem to work fine, but I do have to make the following change to --- a/configure.ac
+++ b/configure.ac
@@ -124,7 +124,8 @@ AC_ARG_ENABLE(caliper,
if test "$enable_caliper" = "yes"; then
PKG_CHECK_MODULES([CALIPER], [caliper], [], [])
CFLAGS="${CFLAGS} ${CALIPER_CFLAGS} "
- LIBS="${LIBS} $(pkg-config --libs-only-L ) -lcaliper-stub -lrt "
+ # Do not use CALIPER_LIBS, only link to libcaliper-stub
+ LIBS="${LIBS} $(pkg-config --libs-only-L caliper) -lcaliper-stub -lrt "
AC_DEFINE([HAVE_CALIPER], [1], [Define if you have libcaliper])
fi was also thinking, would it be a total kludge to add a Alternately, if we pull in the stubs library ourselves, we could perhaps redirect symbols at runtime with |
I wouldn't object to that. |
Something like the below seems to work -- the option only appears if flux-core is built with We could also set some other Hmm, maybe diff --git a/src/cmd/flux-start.c b/src/cmd/flux-start.c
index c40d46f..fa3a755 100644
--- a/src/cmd/flux-start.c
+++ b/src/cmd/flux-start.c
@@ -96,6 +96,10 @@ static struct optparse_option opts[] = {
.usage = "Add comma-separated broker options, e.g. \"-o,-q\"", },
{ .name = "killer-timeout",.key = 'k', .has_arg = 1, .arginfo = "SECONDS",
.usage = "After a broker exits, kill other brokers after SECONDS", },
+#if HAVE_CALIPER
+ { .name = "profile",.key = 'P', .has_arg = 0,
+ .usage = "Run brokers with Caliper profiling enabled", },
+#endif
OPTPARSE_TABLE_END,
};
@@ -387,6 +391,22 @@ struct client *client_create (struct context *ctx, int rank
subprocess_setenvf (cli->p, "PMI_FD", 1, "%d", client_fd);
subprocess_setenvf (cli->p, "PMI_RANK", 1, "%d", rank);
subprocess_setenvf (cli->p, "PMI_SIZE", 1, "%d", ctx->size);
+
+#if HAVE_CALIPER
+ /*
+ * If --profile was used, set or append libcaliper.so in LD_PRELOAD
+ * to subprocess environment, swapping stub symbols for the actual
+ * libcaliper symbols.
+ */
+ if (optparse_hasopt (ctx->opts, "profile")) {
+ const char *pl = getenv ("LD_PRELOAD");
+ subprocess_setenvf (cli->p, "LD_PRELOAD", 1, "%s%s%s",
+ pl ? pl : "",
+ pl ? " ": "",
+ "libcaliper.so");
+ }
+#endif
+
return cli;
fail:
client_destroy (cli);
|
I like where you ended up: |
Ok, something like this?
Built without
|
That looks great to me! |
Closing as we've merged #741. |
note: this is a sanitized branch, commit cleanup is the main difference
This is a very rough cut on tracing for flux. If TAU_PROFILING is
enabled, it turns on some macros that will register flux event
processing with TAU. Getting flux to build, link, and run with TAU is
another matter entirely. I recommend building your own TAU with only
pthread support, then specifying tau_cc.sh as the compiler with only
the options to use shared linking and track pthreads while only
affecting linking. Then when running preload the pthread indirection
library (this should not be necessary, but it is).
Alternately, there is a caliper backend to the basic macros as well,
which can be turned on with the
--with-caliper
option on configure.One still has to have caliper available in appropriate paths, but it's
much easier to get started with this. Unfortunately the data is rather
harder to wrangle from this right now.
Either way, the main point of this is to serve as a starting point for
tracing/profiling in flux rather than a full setup.