This example shows how the name based API for GS can be used to place a set of threads or processes under GS control. In order to use the name based API, an application must announce its components to the Computation Component Set Manager(CCSM). The name based API is the preferred API for GS because it identifies application components across multiple executions of an application.
This example is a descendent of the signal pipeline under group scheduling. It is recommended to examine that example first. It is located here:
Signal Pipeline Group Scheduling
CCSM uses component sets and composite sets. A component set contains a single system component. A composite set contains multiple sets. In this example, a composite set named “pipeline_group” is created. A component set is created for each of the threads in the pipeline and each of the component sets are added to the composite set. The component sets are named as ‘thread-0’, ‘thread-1’, etc.
CCSM is acting as a namespace for GS. It lets group scheduling look up a task by name.
The source for this example is located at:
$KUSPINSTALL/examples/sigpipe_gsched_ccsm/sigpipe.c
In this example, code located in “use_ccsm” and “use_gs” if-statements is used.
The “pipeline_group” composit set is created near the top of the main function:
if(use_ccsm) {
ccsm_fd = ccsm_open();
if (ccsm_fd < 0) {
perror("ccsm_fd");
return 1;
}
if (ccsm_create_set(ccsm_fd, "pipeline_group", 0)) {
perror("create set");
return 1;
}
}
Like GS, to use CCSM, a file descriptor that refers to CCSM must first be opened. After the file descriptor is opened, a composit set named “pipeline_group” is created by calling ccsm_create_set.
As in the previous example, we must still create a group that represents this application under group scheduling. The group is created near the top of the main function:
if(use_gs) {
grp_fd = grp_open();
if (grp_fd < 0) {
perror("grp_fd");
return 1;
}
if (grp_create_group(grp_fd, "pipeline_group", "sdf_seq")) {
perror("create group");
return 1;
}
/* This could be done after all of the threads have been
* added to the group.
*/
if(gsched_install_group(grp_fd, "pipeline_group", "pipeline_group_mem")) {
perror("install group");
return 1;
}
}
The component set for each thread is created at the top of the thread_code function:
if(use_ccsm) {
printf("Creating component for T-%d\n", id);
ccsm_create_component_self(ccsm_fd, name);
printf("Adding T-%d to the set\n", id);
ccsm_add_member(ccsm_fd, "pipeline_group", name);
}
First, a call``ccsm_create_component_self`` creates a component set which contains the current thread. Recall, from the previous example, that ‘name’ is just a name generated by the progrm for this thread, ie: thread-0, ‘thread-1’, etc.
Under CCSM, every set, regardless of whether it is a component set or a composit set, must be uniquely identified to the system. This is a different policy than GS. Under GS, each group is uniquely identified to the system but members of different groups may have the same member names.
Finally, the new component set is added to the composit set that was previously created using ccsm_add_member.
In this example, the GS group name and the CCSM composit set name are the same. However, that is not strictly necessary. The interaction between GS and CCSM depends purely upon the names of the component sets. For this interaction to occur it is not necessary to create the composit set. However, the composit set does allow for the entire computation to be referred to as a whole. This is useful for gathering data about an application.
The thread is added to group scheduling immediately following the creating of the component set, in the thread_code function:
if(use_gs) {
/* If we are using ccsm then we can name the thread. */
if(use_ccsm) {
/* Add the thread to group scheduling by name. */
printf("Adding T-%d to the group by name\n", id);
grp_name_join_group(grp_fd, "pipeline_group", name, 0);
} else {
/* Add the thread to group scheduling using its pid */
printf("adding T-%d to the group by pid\n", id);
grp_pid_join_group(grp_fd, "pipeline_group", tidlist[id], name);
}
// Lower priority is better
gsched_set_member_param_int(grp_fd, "pipeline_group", name, pipeline_len - id);
}
The example is using GS and CCSM. Therefore, the grp_name_join_group function will be called. This function informs group scheduling that there exists a task with the given name that should be added to the “pipeline_group”. There is no need to specify which task has this name because we have already identified the task to CCSM.
A bash script is provided to run the example. It will execute the program and perform postprocessing. Use:
./run
Optionally, the program can be run without postprocessing using:
./run exec
Also, the postprocessing can be run by itself u sing:
./run postprocess
Recall that in previous examples, to filter the DSKI events generated by the application, this filter was used:
filters = [
task(
ccsm_name = "trace-me"
)
]
child_alias = "trace-me"
The primary disadvantage of using this setup is that it is too coarse grained. In the sigpipe_gsched example, events from irrelevant threads are captured. These threads include the main thread that spawns the pipeline threads and the DSUI threads that run behind the scenes. It is better to filter events for only the pipeline threads(the threads created by the main thread).
In this example, the filter looks slightly different:
filters = [
task(
ccsm_name = "pipeline_group"
)
]
This filter refers directly to the CCSM composit set that we created called “pipeline_group”. Only events from components within this set will be recorded and only the pipeline threads were placed within this set.
A narrative of what CCSM actions are being taken is created in the file ccsm.text.
From the same events that construct the narrative, a graph of the ccsm sets is generated in the file ccsm.png. Pygraphviz is used to construct the graph.
The code that produces these files is located in:
$KUSPROOT/subsystems/datastreams/postprocess/filters/ccsmfilter.py