logging in ringbuffer optimieren mit stringindex statt strings



  • Hallo

    Ich habe folgende Idee und könnte noch ein paar Ideen zur Umsetzung vertragen.

    Es geht um einen erweiterten Logging Mechanismus.

    void myLog( const int iLogLevel, const char* const pcFormat, ... )
    {
      va_list Args;
    
      char pcBufferMessage[MAX_LOG_MESSAGE_BUFFER_SIZE];
    
      va_start( Args, pcFormat );
      (void)vsnprintf( pcBufferMessage, LOG_MAX_LOG_MESSAGE_BUFFER_SIZE, pcFormat, Args );
      va_end( Args );
    
      if ( sLogInfo.eOutput & LOG_OUTPUT_BUFFER )
      {
        char *pcTmp= NULL;
        pcTmp = malloc( strlen( pcBufferMessage ) ); /* will be freed if removen from ringbuffer */
        strcpy( pcTmp, pcBufferMessage );
        RingBufferAdd( &sLogBuffer, pcTmp );    
      }
    
      /* Test if the loglevel is to low */
      if ( sLogInfo.iLevel < iLogLevel )
      {
        /* loglevel to low */
        return;
      }
    
      if ( sLogInfo.eOutput & LOG_OUTPUT_STDOUT )
      {
        printf( "%s\n", pcBufferMessage );
      }
    
      if ( sLogInfo.eOutput & LOG_OUTPUT_SYSLOG )
      {
        syslog( iLogLevel, "%s", pcBufferMessage );
      }
    }
    

    Wie man sieht werden die Nachrichten nicht nur über syslog oder printf ausgegeben sondern auch in einen RingBuffer geschrieben.
    Der Ringbuffer wird auch befüllt selbst wenn das loglevel zu gering ist. Hintergrund ist das ich auch noch an die Logausgeben ran kommen will die in der Vergangenheit liegen und selbst wenn das loglevel zu niedrig war.

    Aus Performancegründen will ich aber nicht die ganzen Strings im Ringbuffer speichern.
    So lange die Strings im Textsegent liegen wäre das ja auch alles noch ok. Für dynamische Strings reicht es aber nicht wenn ich die Pointer speichere.

    Eine Idee ist es nun das ich alle strings in einem Struct speichere und noch einen Index rum reiche.

    typedef struct _log_message_index_s
    {
      const char * const pcName;
      int iParameter;
    } log_message_index_s;
    
    static log_message_index_s pcMessages[]=
    {
    …
        { "Test Message", 0 },
        { "Message with one Param %d", 1 },
    …
    }
    

    Dann würde mein Prototype so aus sehen:

    void myLog( const int iLogLevel, const int iMessage, ... )
    

    Problem ist natürlich das ich die Parameter trotzdem kopieren muss.
    Bin noch am Überlegen ob ich dort spezielle Prototypen mit "einem Int" "einem string" als Parameter mache und somit das dynamisch minimiere.

    Für LogMessages ohne Parameter würde das ganze ein deutlichen Performance Gewinn bedeuten. Je mehr dynamische Inhalte, desto aufwendiger wird es.

    Das ganze static log_message_index_s pcMessages würde ich dann über einen Preprocessor auf bauen.

    Macht das ganze Sinn und habt Ihr es schon mal so gemacht?



  • decembersoul schrieb:

    Aus Performancegründen will ich aber nicht die ganzen Strings im Ringbuffer speichern.

    Wieso?

    Performance ist egal - du kopierst hier nur minimal bytes hin und her. Die Allokationen lassen sich ja entfernen wenn du eh einen Buffer haben willst - den limitierst du auf N Einträge und fertig.
    Oder willst du wirklich alle Logmessages ewig speichern? Oder reichen dir eh die letzten 100?

    Weil das kopieren in den RAM ist soviel schneller als das printf/syslog...



  • Ja ich glaube ich muss wirklich mal Zeitmessungen durchführen.

    Mein Ringbuffer speichert wirklich nur x Nachrichten und man könnte die wirklich auf z.B. 50 Zeichen begrenzen.

    Jedoch habe ich dann immer noch strncmp und vsnprintf drinnen.
    Sicher kann man diese beiden Schritte auch direkt vereinen so das vsnprintf direkt in den Speicher vom Ringbuffer schreibt.



  • Kann ich an einem "char* text" erkennen ob er auf ein Textsegment zeigt und damit "immer" gültig ist?

    Es macht ja einen Unterschied

    printf("Text liegt im Textsegent und ist immer gültig");

    oder

    char text[25];
    strcpy(&text, "copy test");
    printf(text); /* dynamischer Text */

    Beispiel:

    #include <stdio.h>
    
    char *define_string()
    {
      return (char*)"Hello2";
    }
    
    void print_string( char *text )
    {
      printf( "%s\n", text );
    }
    
    int main( int argc, char **argv )
    {
      char *address1= (char*)"Hello";
      /*(char*) address2= (char*)"Hello Welt";
      printf( "%p\n", address1 );
      printf( "%p\n", address2 );*/
    
      print_string( address1 );
      print_string( define_string() );
    }
    


  • decembersoul schrieb:

    if ( sLogInfo.eOutput & LOG_OUTPUT_BUFFER )
      {
        char *pcTmp= NULL;
        pcTmp = malloc( strlen( pcBufferMessage ) ); /* will be freed if removen from ringbuffer */
        strcpy( pcTmp, pcBufferMessage );
        RingBufferAdd( &sLogBuffer, pcTmp );    
      }
    
    if ( sLogInfo.eOutput & LOG_OUTPUT_BUFFER )
        RingBufferAdd( &sLogBuffer, strdup(pcBufferMessage) );
    

    decembersoul schrieb:

    if ( sLogInfo.eOutput & LOG_OUTPUT_STDOUT )
      {
        printf( "%s\n", pcBufferMessage );
      }
    
    if ( sLogInfo.eOutput & LOG_OUTPUT_STDOUT )
        puts( pcBufferMessage );
    

    Ciao
    MM



  • ok danke, ich gebe zu das es nur Ausschnitte sind.

    Die myLog hat eigentlich noch einige andere Parameter wie __FILE__, pid usw, welche dann eventuell noch mit bei dem printf mit ausgeben werden.

    Dazu kommt das ich kein malloc verwende sondern ein eigenes welches Speicherüberprüfungen macht und strdup nicht erlaubt ist.
    Habe meine Fkt die sonst 100 Zeile sind auf 35 Zeilen reduziert.

    Gebe aber zu das an einer Stelle wirklich puts besser ist.

    Trotzdem danke für Deinen Input



  • decembersoul schrieb:

    Dazu kommt das ich kein malloc verwende sondern ein eigenes welches Speicherüberprüfungen macht

    ??

    Ansonsten: allokiere den Buffer auf einmal beim Starten und fülle es mit 0 - dann sind alle Zeiger immer gueltig und du kannst immer alle ausgeben - bzw. an der Länge erkennst du ob es ein echter logeintrag ist oder nur ein platzhalter.

    das ganze in einem char*-Array also char** und eine index variable die bei jedem neuen eintrag sich erhöht: index = (index+1)%N;
    wobei N die Max anzahl an Einträgen im Buffer ist.


Anmelden zum Antworten