[Toybox] [PATCH] fix dmesg default size/level filtering/performance

Isaac Dunham ibid.ag at gmail.com
Mon Nov 24 19:10:52 PST 2014


On Mon, Nov 24, 2014 at 05:26:06PM -0800, enh wrote:
> * the kernel buffer hasn't defaulted to 16KiB for a very long time.
> i'm not sure why the original code said < 2 rather than <= 0 (or 1KiB,
> say), but i've left that as it was.
> 
> * there's also a bug with the filtering out of level markers; they can
> be more than one digit. (this is true of all kernels, not just Android
> ones.)
> 
> * finally, the use of xputc for every character makes the toybox dmesg
> human-noticeably slow. writing line at a time is orders of magnitude
> faster/fewer syscalls.
> 
> here's the patch, which attempts to imitate your style:
> diff --git a/toys/lsb/dmesg.c b/toys/lsb/dmesg.c
> index 1003256..d4a2b66 100644
> --- a/toys/lsb/dmesg.c
> +++ b/toys/lsb/dmesg.c
> @@ -15,7 +15,7 @@ config DMESG
>      Print or control the kernel ring buffer.
> 
>      -n Set kernel logging level (1-9).
> -    -s Size of buffer to read (in bytes), default 16384.
> +    -s Size of buffer to read (in bytes), default kernel buffer size.
>      -c Clear the ring buffer after printing.
>  */
> 
> @@ -34,22 +34,34 @@ void dmesg_main(void)
>    if (toys.optflags & 2) {
>      if (klogctl(8, NULL, TT.level)) error_exit("klogctl");
>    } else {
> -    int size, i, last = '\n';
> -    char *data;
> +    int size, i;
> +    char *data, *end;
> 
>      // Figure out how much data we need, and fetch it.
>      size = TT.size;
> -    if (size<2) size = 16384;
> +    if (size < 2) size = klogctl(10, 0, 0); // SYSLOG_ACTION_SIZE_BUFFER.
> +    if (size < 0) size = 16384;
>      data = xmalloc(size);
>      size = klogctl(3 + (toys.optflags&1), data, size);
>      if (size < 0) error_exit("klogctl");
> 
> -    // Display data, filtering out level markers.
> +    // Display data, filtering out level markers (<\d+>).
>      for (i=0; i<size; ) {
> -      if (last=='\n' && data[i]=='<') i += 3;
> -      else xputc(last = data[i++]);
> +      if (data[i]=='<') {
> +        end = strchr(data+i, '>');
> +        if (end) i = end-data+1;
I presume the theory here is that log levels might eventually end up going
above 8, despite the documentation implying otherwise?
And of course everything assumes that < and > are off-limits for the contents.

> +      } else {
> +        end = strchr(data+i, '\n');
> +        if (end) {
> +          xwrite(1, data+i, end-(data+i)+1);
> +          i += end - (data+i) + 1;

Somehow this whole bit reminds me of something I wrote not long ago,
where I took care of unwanted strings by moving the memory contents 
towards the start.
Applied here, it might look like this:

void memback(long delbytes, char *string)
{
  // could be adjusted to not need strlen() in our case...
  memmove(string, string + delbytes, strlen(string) + delbytes);
}

...
  while ((cur = strchr(cur, '<') != 0) {
    memback(3, cur);
  }
 

This will call memmove() a lot; on the other hand, it can call write once.

> +        } else {
> +          xwrite(1, data+i, size-i);
> +          xputc('\n');
> +          i = size;

I'm guessing you want "xwriteall()" instead of "xwrite()"; 
xwriteall retries until everything has been written.
> +        }
> +      }
>      }
> -    if (last!='\n') xputc('\n');
>      if (CFG_TOYBOX_FREE) free(data);
>    }
>  }
> 
> i'm assuming no one actually cares about the old Android "implicit -r"
> behavior. if i get a complaint, adding -r is trivial. (once i learn
> how to add an option at all :-) )

Adding an option is simple:

-USE_DMESG(NEWTOY(dmesg, "s#n#c", TOYFLAG_BIN)
+USE_DMESG(NEWTOY(dmesg, "s#n#cr", TOYFLAG_BIN)
...
     -n  Set kernel logging level (1-9).
+    -r  Print the raw message buffer.
     -s  Size of buffer to read (in bytes), default 16384.
...
+  if (toys.optflags&FLAG_r) {
+    //write the buffer in its entirety
+  }

(I suppose that this could be done with a single call to xwriteall)
www/code.html has more on how to write things for toybox.


And I notice now that dmesg doesn't use the FLAG_* macros, but
instead hardcodes options by their offset in the optsring.
It was last touched about 2 years ago just after the FLAG_* macros,
so that isn't surprising.

 1416885052.0


More information about the Toybox mailing list