X-Git-Url: http://git.liburcu.org/?a=blobdiff_plain;f=lttv%2Flttv%2Fsync%2Fsync_chain_lttv.c;h=bb49bbd20b86c4a3484b660181d2731a382aa13e;hb=df64b31664467d7217fa08fcdee423577856b38a;hp=2003e95fd7ca24d29481a7775dcad2f60901329a;hpb=9a9ca632e32af79f5f77894ef6e981ac0138102a;p=lttv.git diff --git a/lttv/lttv/sync/sync_chain_lttv.c b/lttv/lttv/sync/sync_chain_lttv.c index 2003e95f..bb49bbd2 100644 --- a/lttv/lttv/sync/sync_chain_lttv.c +++ b/lttv/lttv/sync/sync_chain_lttv.c @@ -1,27 +1,29 @@ /* This file is part of the Linux Trace Toolkit viewer - * Copyright (C) 2009 Benjamin Poirier + * Copyright (C) 2009, 2010 Benjamin Poirier * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License Version 2 as - * published by the Free Software Foundation; + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or (at + * your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, - * MA 02111-1307, USA. + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . */ +#define _ISOC99_SOURCE + #ifdef HAVE_CONFIG_H #include #endif #include #include +#include #include #include #include @@ -33,90 +35,144 @@ #include #include -#include "sync_chain_lttv.h" - -#ifndef g_info -#define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format) -#endif +#include "event_processing_lttng_standard.h" +#include "event_processing_lttng_null.h" +#include "event_matching_tcp.h" +#include "event_matching_broadcast.h" +#include "event_matching_distributor.h" +#include "event_analysis_chull.h" +#include "event_analysis_linreg.h" +#include "event_analysis_eval.h" +#include "factor_reduction_accuracy.h" +#include "sync_chain.h" +#include "sync_chain_lttv.h" static void init(); static void destroy(); -static void gfAppendAnalysisName(gpointer data, gpointer user_data); - -static gboolean optionSync; -static gboolean optionSyncStats; -static gboolean optionSyncNull; -static char* optionSyncAnalysis; -static gboolean optionSyncGraphs; -static char* optionSyncGraphsDir; +static void gfAddModuleOption(gpointer data, gpointer user_data); +static void gfRemoveModuleOption(gpointer data, gpointer user_data); + +static ModuleOption optionSync= { + .longName= "sync", + .hasArg= NO_ARG, + .optionHelp= "synchronize the time between the traces", +}; +static ModuleOption optionSyncStats= { + .longName= "sync-stats", + .hasArg= NO_ARG, + .optionHelp= "print statistics about the time synchronization", +}; +static ModuleOption optionSyncNull= { + .longName= "sync-null", + .hasArg= NO_ARG, + .optionHelp= "read the events but do not perform any processing", +}; +static GString* analysisModulesNames; +static ModuleOption optionSyncAnalysis= { + .longName= "sync-analysis", + .hasArg= REQUIRED_ARG, + .optionHelp= "specify the algorithm to use for event analysis", +}; +static GString* reductionModulesNames; +static ModuleOption optionSyncReduction= { + .longName= "sync-reduction", + .hasArg= REQUIRED_ARG, + .optionHelp= "specify the algorithm to use for factor reduction", +}; +static ModuleOption optionSyncGraphs= { + .longName= "sync-graphs", + .hasArg= NO_ARG, + .optionHelp= "output gnuplot graph showing synchronization points", +}; static char graphsDir[20]; - -GQueue processingModules= G_QUEUE_INIT; -GQueue matchingModules= G_QUEUE_INIT; -GQueue analysisModules= G_QUEUE_INIT; +static ModuleOption optionSyncGraphsDir= { + .longName= "sync-graphs-dir", + .hasArg= REQUIRED_ARG, + .optionHelp= "specify the directory where to store the graphs", +}; /* * Module init function * - * This function is declared to be the module initialization function. Event - * modules are registered with a "constructor (102)" attribute except one in - * each class (processing, matching, analysis) which is chosen to be the - * default and which is registered with a "constructor (101)" attribute. - * Constructors with no priority are called after constructors with - * priorities. The result is that the list of event modules is known when this - * function is executed. + * This function is declared to be the module initialization function. */ static void init() { - GString* analysisModulesNames; int retval; - - g_debug("\t\t\tXXXX sync init\n"); - - optionSync= FALSE; - lttv_option_add("sync", '\0', "synchronize the time between the traces" , - "none", LTTV_OPT_NONE, &optionSync, NULL, NULL); - - optionSyncStats= FALSE; - lttv_option_add("sync-stats", '\0', "print statistics about the time " - "synchronization", "none", LTTV_OPT_NONE, &optionSyncStats, NULL, - NULL); - - optionSyncNull= FALSE; - lttv_option_add("sync-null", '\0', "read the events but do not perform " - "any processing", "none", LTTV_OPT_NONE, &optionSyncNull, NULL, NULL); - - g_assert(g_queue_get_length(&analysisModules) > 0); - optionSyncAnalysis= ((AnalysisModule*) - g_queue_peek_head(&analysisModules))->name; - analysisModulesNames= g_string_new(""); - g_queue_foreach(&analysisModules, &gfAppendAnalysisName, - analysisModulesNames); - // remove the last ", " - g_string_truncate(analysisModulesNames, analysisModulesNames->len - 2); - lttv_option_add("sync-analysis", '\0', "specify the algorithm to use for " - "event analysis" , analysisModulesNames->str, LTTV_OPT_STRING, - &optionSyncAnalysis, NULL, NULL); - g_string_free(analysisModulesNames, TRUE); - - optionSyncGraphs= FALSE; - lttv_option_add("sync-graphs", '\0', "output gnuplot graph showing " - "synchronization points", "none", LTTV_OPT_NONE, &optionSyncGraphs, - NULL, NULL); + unsigned int i; + const struct + { + GQueue* modules; + ModuleOption* option; + size_t nameOffset; + GString** names; + void (*gfAppendName)(gpointer data, gpointer user_data); + } loopValues[]= { + {&analysisModules, &optionSyncAnalysis, offsetof(AnalysisModule, + name), &analysisModulesNames, &gfAppendAnalysisName}, + {&reductionModules, &optionSyncReduction, offsetof(ReductionModule, + name), &reductionModulesNames, &gfAppendReductionName}, + }; + + g_debug("Sync init"); + + /* + * Initialize event modules + * Call the "constructor" or initialization function of each event module + * so it can register itself. This must be done before elements in + * processingModules, matchingModules, analysisModules or moduleOptions + * are accessed. + */ + registerProcessingLTTVStandard(); + registerProcessingLTTVNull(); + + registerMatchingTCP(); + registerMatchingBroadcast(); + registerMatchingDistributor(); + + registerAnalysisCHull(); + registerAnalysisLinReg(); + registerAnalysisEval(); + + registerReductionAccuracy(); + + // Build module names lists for option and help string + for (i= 0; i < ARRAY_SIZE(loopValues); i++) + { + g_assert(g_queue_get_length(loopValues[i].modules) > 0); + loopValues[i].option->arg= (char*)(*(void**) + g_queue_peek_head(loopValues[i].modules) + + loopValues[i].nameOffset); + *loopValues[i].names= g_string_new(""); + g_queue_foreach(loopValues[i].modules, loopValues[i].gfAppendName, + *loopValues[i].names); + // remove the last ", " + g_string_truncate(*loopValues[i].names, (*loopValues[i].names)->len - + 2); + loopValues[i].option->argHelp= (*loopValues[i].names)->str; + } retval= snprintf(graphsDir, sizeof(graphsDir), "graphs-%d", getpid()); if (retval > sizeof(graphsDir) - 1) { graphsDir[sizeof(graphsDir) - 1]= '\0'; } - optionSyncGraphsDir= graphsDir; - lttv_option_add("sync-graphs-dir", '\0', "specify the directory where to" - " store the graphs", graphsDir, LTTV_OPT_STRING, &optionSyncGraphsDir, - NULL, NULL); + optionSyncGraphsDir.arg= graphsDir; + optionSyncGraphsDir.argHelp= graphsDir; + + g_queue_push_head(&moduleOptions, &optionSyncGraphsDir); + g_queue_push_head(&moduleOptions, &optionSyncGraphs); + g_queue_push_head(&moduleOptions, &optionSyncReduction); + g_queue_push_head(&moduleOptions, &optionSyncAnalysis); + g_queue_push_head(&moduleOptions, &optionSyncNull); + g_queue_push_head(&moduleOptions, &optionSyncStats); + g_queue_push_head(&moduleOptions, &optionSync); + + g_queue_foreach(&moduleOptions, &gfAddModuleOption, NULL); } @@ -125,14 +181,17 @@ static void init() */ static void destroy() { - g_debug("\t\t\tXXXX sync destroy\n"); - - lttv_option_remove("sync"); - lttv_option_remove("sync-stats"); - lttv_option_remove("sync-null"); - lttv_option_remove("sync-analysis"); - lttv_option_remove("sync-graphs"); - lttv_option_remove("sync-graphs-dir"); + g_debug("Sync destroy"); + + g_queue_foreach(&moduleOptions, &gfRemoveModuleOption, NULL); + g_string_free(analysisModulesNames, TRUE); + g_string_free(reductionModulesNames, TRUE); + + g_queue_clear(&processingModules); + g_queue_clear(&matchingModules); + g_queue_clear(&analysisModules); + g_queue_clear(&reductionModules); + g_queue_clear(&moduleOptions); } @@ -143,23 +202,30 @@ static void destroy() * * Args: * traceSetContext: traceset + * + * Returns: + * false if synchronization was not performed, true otherwise */ -void syncTraceset(LttvTracesetContext* const traceSetContext) +bool syncTraceset(LttvTracesetContext* const traceSetContext) { SyncState* syncState; struct timeval startTime, endTime; struct rusage startUsage, endUsage; GList* result; - FILE* graphsStream; + unsigned int i; + AllFactors* allFactors; + GArray* factors; + double minOffset, minDrift; + unsigned int refFreqTrace; int retval; - if (optionSync == FALSE) + if (!optionSync.present) { g_debug("Not synchronizing traceset because option is disabled"); - return; + return false; } - if (optionSyncStats) + if (optionSyncStats.present) { gettimeofday(&startTime, 0); getrusage(RUSAGE_SELF, &startUsage); @@ -167,9 +233,8 @@ void syncTraceset(LttvTracesetContext* const traceSetContext) // Initialize data structures syncState= malloc(sizeof(SyncState)); - syncState->traceNb= lttv_traceset_number(traceSetContext->ts); - if (optionSyncStats) + if (optionSyncStats.present) { syncState->stats= true; } @@ -178,18 +243,22 @@ void syncTraceset(LttvTracesetContext* const traceSetContext) syncState->stats= false; } - if (optionSyncGraphs) + if (!optionSyncNull.present && optionSyncGraphs.present) { - syncState->graphs= optionSyncGraphsDir; + // Create the graph directory right away in case the module initialization + // functions have something to write in it. + syncState->graphsDir= optionSyncGraphsDir.arg; + syncState->graphsStream= createGraphsDir(syncState->graphsDir); } else { - syncState->graphs= NULL; + syncState->graphsStream= NULL; + syncState->graphsDir= NULL; } - // Identify and initialize processing module + // Identify and initialize modules syncState->processingData= NULL; - if (optionSyncNull) + if (optionSyncNull.present) { result= g_queue_find_custom(&processingModules, "LTTV-null", &gcfCompareProcessing); @@ -202,42 +271,13 @@ void syncTraceset(LttvTracesetContext* const traceSetContext) g_assert(result != NULL); syncState->processingModule= (ProcessingModule*) result->data; - graphsStream= NULL; - if (syncState->graphs && - syncState->processingModule->writeProcessingGraphsPlots != NULL) - { - char* cwd; - int graphsFp; - - // Create the graph directory right away in case the module initialization - // functions have something to write in it. - cwd= changeToGraphDir(syncState->graphs); - - if ((graphsFp= open("graphs.gnu", O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | - S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH - | S_IWOTH | S_IXOTH)) == -1) - { - g_error(strerror(errno)); - } - if ((graphsStream= fdopen(graphsFp, "w")) == NULL) - { - g_error(strerror(errno)); - } - - retval= chdir(cwd); - if (retval == -1) - { - g_error(strerror(errno)); - } - free(cwd); - } - - // Identify matching and analysis modules - g_assert(g_queue_get_length(&matchingModules) == 1); - syncState->matchingModule= (MatchingModule*) - g_queue_peek_head(&matchingModules); + syncState->matchingData= NULL; + result= g_queue_find_custom(&matchingModules, "TCP", &gcfCompareMatching); + g_assert(result != NULL); + syncState->matchingModule= (MatchingModule*) result->data; - result= g_queue_find_custom(&analysisModules, optionSyncAnalysis, + syncState->analysisData= NULL; + result= g_queue_find_custom(&analysisModules, optionSyncAnalysis.arg, &gcfCompareAnalysis); if (result != NULL) { @@ -245,18 +285,27 @@ void syncTraceset(LttvTracesetContext* const traceSetContext) } else { - g_error("Analysis module '%s' not found", optionSyncAnalysis); + g_error("Analysis module '%s' not found", optionSyncAnalysis.arg); } - syncState->processingModule->initProcessing(syncState, traceSetContext); - - syncState->matchingData= NULL; - syncState->analysisData= NULL; + syncState->reductionData= NULL; + result= g_queue_find_custom(&reductionModules, optionSyncReduction.arg, + &gcfCompareReduction); + if (result != NULL) + { + syncState->reductionModule= (ReductionModule*) result->data; + } + else + { + g_error("Reduction module '%s' not found", optionSyncReduction.arg); + } - if (!optionSyncNull) + syncState->processingModule->initProcessing(syncState, traceSetContext); + if (!optionSyncNull.present) { syncState->matchingModule->initMatching(syncState); syncState->analysisModule->initAnalysis(syncState); + syncState->reductionModule->initReduction(syncState); } // Process traceset @@ -265,69 +314,101 @@ void syncTraceset(LttvTracesetContext* const traceSetContext) G_MAXULONG, NULL); lttv_process_traceset_seek_time(traceSetContext, ltt_time_zero); - syncState->processingModule->finalizeProcessing(syncState); - - // Write graphs file - if (graphsStream != NULL) + // Obtain, reduce, adjust and set correction factors + allFactors= syncState->processingModule->finalizeProcessing(syncState); + factors= syncState->reductionModule->finalizeReduction(syncState, + allFactors); + freeAllFactors(allFactors, syncState->traceNb); + + /* The offsets are adjusted so the lowest one is 0. This is done because + * of a Lttv specific limitation: events cannot have negative times. By + * having non-negative offsets, events cannot be moved backwards to + * negative times. + */ + minOffset= 0; + for (i= 0; i < syncState->traceNb; i++) { - unsigned int i, j; + minOffset= MIN(g_array_index(factors, Factors, i).offset, minOffset); + } - fprintf(graphsStream, - "#!/usr/bin/gnuplot\n\n" - "set terminal postscript eps color size 8in,6in\n"); + for (i= 0; i < syncState->traceNb; i++) + { + g_array_index(factors, Factors, i).offset-= minOffset; + } - // Cover the upper triangular matrix, i is the reference node. - for (i= 0; i < syncState->traceNb; i++) + /* Because the timestamps are corrected at the TSC level (not at the + * LttTime level) all trace frequencies must be made equal. We use the + * frequency of the system with the lowest drift + */ + minDrift= INFINITY; + refFreqTrace= 0; + for (i= 0; i < syncState->traceNb; i++) + { + if (g_array_index(factors, Factors, i).drift < minDrift) { - for (j= i + 1; j < syncState->traceNb; j++) - { - long pos; - - fprintf(graphsStream, - "\nset output \"%03d-%03d.eps\"\n" - "plot \\\n", i, j); - - syncState->processingModule->writeProcessingGraphsPlots(graphsStream, - syncState, i, j); - - // Remove the ", \\\n" from the last graph plot line - fflush(graphsStream); - pos= ftell(graphsStream); - if (ftruncate(fileno(graphsStream), pos - 4) == -1) - { - g_error(strerror(errno)); - } - if (fseek(graphsStream, 0, SEEK_END) == -1) - { - g_error(strerror(errno)); - } - - fprintf(graphsStream, - "\nset output \"%1$03d-%2$03d.eps\"\n" - "set key inside right bottom\n" - "set title \"\"\n" - "set xlabel \"Clock %1$u\"\n" - "set xtics nomirror\n" - "set ylabel \"Clock %2$u\"\n" - "set ytics nomirror\n", i, j); - - syncState->processingModule->writeProcessingGraphsOptions(graphsStream, - syncState, i, j); - - fprintf(graphsStream, - "replot\n"); - } + minDrift= g_array_index(factors, Factors, i).drift; + refFreqTrace= i; } + } + g_assert(syncState->traceNb == 0 || minDrift != INFINITY); + + // Write the factors to the LttTrace structures + for (i= 0; i < syncState->traceNb; i++) + { + LttTrace* t; + Factors* traceFactors; + + t= traceSetContext->traces[i]->t; + traceFactors= &g_array_index(factors, Factors, i); + + t->drift= traceFactors->drift; + t->offset= traceFactors->offset; + t->start_freq= traceSetContext->traces[refFreqTrace]->t->start_freq; + t->freq_scale= traceSetContext->traces[refFreqTrace]->t->freq_scale; + t->start_time_from_tsc = + ltt_time_from_uint64(tsc_to_uint64(t->freq_scale, t->start_freq, + t->drift * t->start_tsc + t->offset)); + } + + g_array_free(factors, TRUE); + + lttv_traceset_context_compute_time_span(traceSetContext, + &traceSetContext->time_span); + + g_debug("traceset start %ld.%09ld end %ld.%09ld", + traceSetContext->time_span.start_time.tv_sec, + traceSetContext->time_span.start_time.tv_nsec, + traceSetContext->time_span.end_time.tv_sec, + traceSetContext->time_span.end_time.tv_nsec); - if (fclose(graphsStream) != 0) + // Write graphs file + if (!optionSyncNull.present && optionSyncGraphs.present) + { + writeGraphsScript(syncState); + + if (fclose(syncState->graphsStream) != 0) { - g_error(strerror(errno)); + g_error("%s", strerror(errno)); } } - if (syncState->processingModule->printProcessingStats != NULL) + if (!optionSyncNull.present && optionSyncStats.present) { - syncState->processingModule->printProcessingStats(syncState); + printStats(syncState); + + printf("Resulting synchronization factors:\n"); + for (i= 0; i < syncState->traceNb; i++) + { + LttTrace* t; + + t= traceSetContext->traces[i]->t; + + printf("\ttrace %u drift= %g offset= %g (%f) start time= %ld.%09ld\n", + i, t->drift, t->offset, (double) tsc_to_uint64(t->freq_scale, + t->start_freq, t->offset) / NANOSECONDS_PER_SECOND, + t->start_time_from_tsc.tv_sec, + t->start_time_from_tsc.tv_nsec); + } } syncState->processingModule->destroyProcessing(syncState); @@ -339,10 +420,14 @@ void syncTraceset(LttvTracesetContext* const traceSetContext) { syncState->analysisModule->destroyAnalysis(syncState); } + if (syncState->reductionModule != NULL) + { + syncState->reductionModule->destroyReduction(syncState); + } free(syncState); - if (optionSyncStats) + if (optionSyncStats.present) { gettimeofday(&endTime, 0); retval= getrusage(RUSAGE_SELF, &endUsage); @@ -358,154 +443,60 @@ void syncTraceset(LttvTracesetContext* const traceSetContext) printf("\tsystem time: %ld.%06ld\n", endUsage.ru_stime.tv_sec, endUsage.ru_stime.tv_usec); } -} - - -/* - * Calculate the elapsed time between two timeval values - * - * Args: - * end: end time, result is also stored in this structure - * start: start time - */ -void timeDiff(struct timeval* const end, const struct timeval* const start) -{ - if (end->tv_usec >= start->tv_usec) - { - end->tv_sec-= start->tv_sec; - end->tv_usec-= start->tv_usec; - } - else - { - end->tv_sec= end->tv_sec - start->tv_sec - 1; - end->tv_usec= end->tv_usec - start->tv_usec + 1e6; - } -} - - -/* - * A GCompareFunc for g_slist_find_custom() - * - * Args: - * a: ProcessingModule*, element's data - * b: char*, user data to compare against - * - * Returns: - * 0 if the processing module a's name is b - */ -gint gcfCompareProcessing(gconstpointer a, gconstpointer b) -{ - const ProcessingModule* processingModule; - const char* name; - - processingModule= (const ProcessingModule*) a; - name= (const char*) b; - - return strncmp(processingModule->name, name, - strlen(processingModule->name) + 1); -} - - -/* - * A GCompareFunc for g_slist_find_custom() - * - * Args: - * a: MatchingModule*, element's data - * b: char*, user data to compare against - * - * Returns: - * 0 if the matching module a's name is b - */ -gint gcfCompareMatching(gconstpointer a, gconstpointer b) -{ - const MatchingModule* matchingModule; - const char* name; - - matchingModule= (const MatchingModule*) a; - name= (const char*) b; - - return strncmp(matchingModule->name, name, strlen(matchingModule->name) + - 1); -} - - -/* - * A GCompareFunc for g_slist_find_custom() - * - * Args: - * a: AnalysisModule*, element's data - * b: char*, user data to compare against - * - * Returns: - * 0 if the analysis module a's name is b - */ -gint gcfCompareAnalysis(gconstpointer a, gconstpointer b) -{ - const AnalysisModule* analysisModule; - const char* name; - analysisModule= (const AnalysisModule*) a; - name= (const char*) b; - - return strncmp(analysisModule->name, name, strlen(analysisModule->name) + - 1); + return true; } /* * A GFunc for g_queue_foreach() * - * Concatenate analysis module names. - * * Args: - * data: AnalysisModule* - * user_data: GString*, concatenated names + * data: ModuleOption* + * user_data: NULL */ -static void gfAppendAnalysisName(gpointer data, gpointer user_data) +static void gfAddModuleOption(gpointer data, gpointer user_data) { - g_string_append((GString*) user_data, ((AnalysisModule*) data)->name); - g_string_append((GString*) user_data, ", "); + ModuleOption* option= data; + LttvOptionType conversion[]= { + [NO_ARG]= LTTV_OPT_NONE, + [OPTIONAL_ARG]= LTTV_OPT_NONE, + [REQUIRED_ARG]= LTTV_OPT_STRING, + }; + size_t fieldOffset[]= { + [NO_ARG]= offsetof(ModuleOption, present), + [REQUIRED_ARG]= offsetof(ModuleOption, arg), + }; + static const char* argHelpNone= "none"; + + g_assert_cmpuint(sizeof(conversion) / sizeof(*conversion), ==, + HAS_ARG_COUNT); + if (option->hasArg == OPTIONAL_ARG) + { + g_warning("Parameters with optional arguments not supported by the " + "lttv option scheme, parameter '%s' will not be available", + option->longName); + } + else + { + lttv_option_add(option->longName, '\0', option->optionHelp, + option->argHelp ? option->argHelp : argHelpNone, + conversion[option->hasArg], (void*) option + fieldOffset[option->hasArg], + NULL, NULL); + } } /* - * Change to the directory used to hold graphs. Create it if necessary. + * A GFunc for g_queue_foreach() * * Args: - * graph: name of directory - * - * Returns: - * The current working directory before the execution of the function. The - * string must be free'd by the caller. + * data: ModuleOption* + * user_data: NULL */ -char* changeToGraphDir(char* const graphs) +static void gfRemoveModuleOption(gpointer data, gpointer user_data) { - int retval; - char* cwd; - - cwd= getcwd(NULL, 0); - if (cwd == NULL) - { - g_error(strerror(errno)); - } - while ((retval= chdir(graphs)) != 0) - { - if (errno == ENOENT) - { - retval= mkdir(graphs, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | - S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH); - if (retval != 0) - { - g_error(strerror(errno)); - } - } - else - { - g_error(strerror(errno)); - } - } - - return cwd; + lttv_option_remove(((ModuleOption*) data)->longName); }