On Mon, Nov 11, 2013 at 03:06:09PM -0200, Paulo Zanoni wrote: > From: Paulo Zanoni <paulo.r.zanoni@xxxxxxxxx> > > These functions should help you checking for new Kernel error > messages. One of the problems I had while writing the runtime PM test > suite is that when you read the sysfs and debugfs files, the only way > to detect errors is by checking dmesg, so I was always getting SUCCESS > even if the test caught a bug. Also, we have so many debugfs/sysfs > files that it was not easy to discover which file caused the error > messages I was seeing. So this commit adds some infrastructure to > allow us to automatically check for new errors on dmesg. > > Use it like this: > > int main(int argc, char *argv[]) { > int fd, i; > > igt_fixture > fd = kmsg_error_setup(); > > igt_subtest("t1") { > kmsg_error_reset(fd); > do_something(); > kmsg_error_detect(""); > } > > igt_subtest("t2") { > for (i = 0; i < 10; i++) { > char *file_name = get_file(i); > kmsg_error_reset(fd); > process_file(file_name); > kmsg_error_detect(file_name): > } > } > > igt_fixture > kmsg_error_teardown(fd); > } Imo that's the wrong approach. _Every_ test should fail if we end up with errors/backtraces in dmesg. And if you look for very specific stuff (like gpu hang or missed irq warnings) the approach thus far has been to expose that information somehow through debugfs files. That way we're independent from the exact string used in the kernel output. I think the right approach is to add this to the test runner, i.e. piglit. There's already very basic support to capture the (new) dmesg output for each test with the --dmesg option. Have you played around with that and tried to extend it to your liking? -Daniel > > Signed-off-by: Paulo Zanoni <paulo.r.zanoni@xxxxxxxxx> > --- > lib/drmtest.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > lib/drmtest.h | 13 ++++++++++ > 2 files changed, 92 insertions(+) > > diff --git a/lib/drmtest.c b/lib/drmtest.c > index d8fc60f..ebabfd8 100644 > --- a/lib/drmtest.c > +++ b/lib/drmtest.c > @@ -41,6 +41,7 @@ > #include <linux/kd.h> > #include <unistd.h> > #include <sys/wait.h> > +#include <poll.h> > #include "drm_fourcc.h" > > #include "drmtest.h" > @@ -2307,3 +2308,81 @@ void igt_system_suspend_autoresume(void) > ret = system("rtcwake -s 30 -m mem"); > igt_assert(ret == 0); > } > + > +/* The kmsg error detecting functions allow you to catch new error messages from > + * the Kernel. The idea is that you have to call kmsg_error_setup() only once at > + * the beginning, and kmsg_error_teardown() at the end. And for every subtest, > + * you run kmsg_error_reset() at the begin and kmsg_error_detect() at the end: > + * this should make sure that kmsg_error_detect() will only catch the error > + * messages that were introduced after the subtest started. */ > +int kmsg_error_setup(void) > +{ > + int fd = open("/dev/kmsg", O_RDONLY); > + > + igt_assert_f(fd >= 0, "Can't open /dev/kmsg\n"); > + return fd; > +} > + > +void kmsg_error_teardown(int fd) > +{ > + close(fd); > +} > + > +/* You have to call this before running your subtest, so that the next time you > + * call kmsg_error_detect you'll only look at the new kmsg lines. */ > +void kmsg_error_reset(int fd) > +{ > + lseek(fd, 0, SEEK_END); > +} > + > +static void kmsg_error_line_parse(const char *line, const char *error_msg) > +{ > + igt_assert_f(strstr(line, "------------[ cut here ]------------") == 0, > + "%s\n", error_msg); > + igt_assert_f(strstr(line, "*ERROR*") == 0, "%s\n", error_msg); > + igt_assert_f(strstr(line, "BUG: sleeping function called from invalid context at") == 0, > + "%s\n", error_msg); > +} > + > +/* Keep reading the Kernel ring buffer and checking for errors. Stop reading if > + * there's nothing new on the buffer after the timeout. Notice that every time > + * you call this function, the time it will take to return will always be >= the > + * timeout. */ > +void kmsg_error_detect(int fd, int timeout_ms, const char *error_msg) > +{ > + int i, rc; > + int line_size = 128, line_used = 0, buf_size = 128; > + char buf[buf_size]; > + char *line; > + struct pollfd pfd; > + ssize_t readed; > + > + line = malloc(sizeof(char) * line_size); > + igt_assert(line); > + > + pfd.fd = fd; > + pfd.events = POLLIN | POLLPRI; > + > + while (1) { > + pfd.revents = 0; > + rc = poll(&pfd, 1, timeout_ms); > + if (!rc) > + break; > + > + readed = read(fd, &buf, buf_size - 1); > + for (i = 0; i < readed; i++) { > + if (line_used + 1 >= line_size) { > + line = realloc(line, line_size * 2); > + line_size *= 2; > + igt_assert(line); > + } > + line[line_used++] = buf[i]; > + if (buf[i] == '\n') { > + line[line_used] = '\0'; > + kmsg_error_line_parse(line, error_msg); > + line_used = 0; > + } > + } > + } > + free(line); > +} > diff --git a/lib/drmtest.h b/lib/drmtest.h > index a9fd0bc..05e3629 100644 > --- a/lib/drmtest.h > +++ b/lib/drmtest.h > @@ -413,4 +413,17 @@ void igt_enable_prefault(void); > /* suspend and auto-resume system */ > void igt_system_suspend_autoresume(void); > > +/* Returns the fd for the other functions. */ > +int kmsg_error_setup(void); > +/* Closes the fd */ > +void kmsg_error_teardown(int fd); > +/* Skip to the end of the kmsg fd, so that the next time you call > + * kmsg_error_detect() you will only parse the new messages. */ > +void kmsg_error_reset(int fd); > +/* Reads all the new Kernel messages since the last time you called > + * kmsg_error_teardown, and also waits for new messages for timeout_ms. In case > + * we find any error we'll also print error_msg. Uses igt_assert, so no need to > + * check for return values. */ > +void kmsg_error_detect(int fd, int timeout_ms, const char *error_msg); > + > #endif /* DRMTEST_H */ > -- > 1.8.3.1 > > _______________________________________________ > Intel-gfx mailing list > Intel-gfx@xxxxxxxxxxxxxxxxxxxxx > http://lists.freedesktop.org/mailman/listinfo/intel-gfx -- Daniel Vetter Software Engineer, Intel Corporation +41 (0) 79 365 57 48 - http://blog.ffwll.ch _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx