From patchwork Wed Mar 27 05:06:37 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Kenneth Graunke X-Patchwork-Id: 2347681 Return-Path: X-Original-To: patchwork-intel-gfx@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by patchwork1.kernel.org (Postfix) with ESMTP id 2F0EF3FD40 for ; Wed, 27 Mar 2013 06:27:22 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 67525E5F5A for ; Tue, 26 Mar 2013 23:27:22 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from homiemail-a1.g.dreamhost.com (mailbigip.dreamhost.com [208.97.132.5]) by gabe.freedesktop.org (Postfix) with ESMTP id 7C090E6025 for ; Tue, 26 Mar 2013 22:06:02 -0700 (PDT) Received: from homiemail-a1.g.dreamhost.com (localhost [127.0.0.1]) by homiemail-a1.g.dreamhost.com (Postfix) with ESMTP id 9EF4F34806A; Tue, 26 Mar 2013 22:06:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=whitecape.org; h=from:to :cc:subject:date:message-id:mime-version:content-type: content-transfer-encoding; s=whitecape.org; bh=a6YbzeZ3HqIVk7JAY yXyw9PCCEY=; b=dtoMNFVBX1zXpohRDa/rY0eGGz2r0csbr72tdT4IgSVl/jqvh t3Su/rfqwrfd7/zYg++anjUPZNkFQRzG1MzPOmqb2CVNyQ0hrPXwHOI9iqjrL3iT 90yVB9iw4TVkSyqURESYqPuqPAMksMqPnylUwZVIR2kRqNW806dV1Rd4mE= Received: from localhost.localdomain (static-50-43-15-186.bvtn.or.frontiernet.net [50.43.15.186]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) (Authenticated sender: kenneth@whitecape.org) by homiemail-a1.g.dreamhost.com (Postfix) with ESMTPSA id 3949C348062; Tue, 26 Mar 2013 22:06:01 -0700 (PDT) From: Kenneth Graunke To: intel-gfx@lists.freedesktop.org Date: Tue, 26 Mar 2013 22:06:37 -0700 Message-Id: <1364360799-12064-1-git-send-email-kenneth@whitecape.org> X-Mailer: git-send-email 1.8.2 MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH 1/3] intel_perf_counters: a little tool for dumping performance counters. X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: intel-gfx-bounces+patchwork-intel-gfx=patchwork.kernel.org@lists.freedesktop.org Errors-To: intel-gfx-bounces+patchwork-intel-gfx=patchwork.kernel.org@lists.freedesktop.org From: Eric Anholt This reads the GPU's performance counters via MI_REPORT_PERF_COUNT and prints them in a top-style interface. While it can be useful in and of itself, it also documents the performance counters and lets us verify that they're working. Currently, it only supports Ironlake. v2 [Ken]: Rebase on master and fix compilation failures; make it abort on non-Ironlake platforms to avoid GPU hangs; rename from 'chaps' to intel_perf_counters since that acronym isn't used any longer; write the above commit message. --- tools/Makefile.am | 1 + tools/intel_perf_counters.c | 175 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 176 insertions(+) create mode 100644 tools/intel_perf_counters.c diff --git a/tools/Makefile.am b/tools/Makefile.am index bb3328f..e939518 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -12,6 +12,7 @@ bin_PROGRAMS = \ intel_gpu_top \ intel_gpu_time \ intel_gtt \ + intel_perf_counters \ intel_stepping \ intel_reg_checker \ intel_reg_dumper \ diff --git a/tools/intel_perf_counters.c b/tools/intel_perf_counters.c new file mode 100644 index 0000000..53d2ad7 --- /dev/null +++ b/tools/intel_perf_counters.c @@ -0,0 +1,175 @@ +/* + * Copyright © 2010, 2013 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + */ + +#include +#include +#include +#include +#include + +#include "drm.h" +#include "i915_drm.h" +#include "drmtest.h" +#include "intel_gpu_tools.h" +#include "intel_bufmgr.h" +#include "intel_batchbuffer.h" + +#define COUNTER_COUNT 29 + +const char *counter_name[COUNTER_COUNT] = { + "cycles the CS unit is starved", + "cycles the CS unit is stalled", + "cycles the VF unit is starved", + "cycles the VF unit is stalled", + "cycles the VS unit is starved", + "cycles the VS unit is stalled", + "cycles the GS unit is starved", + "cycles the GS unit is stalled", + "cycles the CL unit is starved", + "cycles the CL unit is stalled", + "cycles the SF unit is starved", + "cycles the SF unit is stalled", + "cycles the WZ unit is starved", + "cycles the WZ unit is stalled", + "Z buffer read/write ", + "cycles each EU was active ", + "cycles each EU was suspended ", + "cycles threads loaded all EUs", + "cycles filtering active ", + "cycles PS threads executed ", + "subspans written to RC ", + "bytes read for texture reads ", + "texels returned from sampler ", + "polygons not culled ", + "clocks MASF has valid message", + "64b writes/reads from RC ", + "reads on dataport ", + "clocks MASF has valid msg not consumed by sampler", + "cycles any EU is stalled for math", +}; + +int have_totals = 0; +uint32_t totals[COUNTER_COUNT]; +uint32_t last_counter[COUNTER_COUNT]; +static drm_intel_bufmgr *bufmgr; +struct intel_batchbuffer *batch; + +/* DW0 */ +#define MI_REPORT_PERF_COUNT ((0x26 << 23) | (3 - 2)) +#define MI_COUNTER_SET_0 (0 << 6) +#define MI_COUNTER_SET_1 (1 << 6) +/* DW1 */ +#define MI_COUNTER_ADDRESS_GTT (1 << 0) +/* DW2: report ID */ + +static void +get_counters(void) +{ + int i; + drm_intel_bo *stats_bo; + uint32_t *stats_result; + + stats_bo = drm_intel_bo_alloc(bufmgr, "stats", 4096, 4096); + + BEGIN_BATCH(6); + OUT_BATCH(MI_REPORT_PERF_COUNT | MI_COUNTER_SET_0); + OUT_RELOC(stats_bo, + I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION, + 0); + OUT_BATCH(0); + + OUT_BATCH(MI_REPORT_PERF_COUNT | MI_COUNTER_SET_1); + OUT_RELOC(stats_bo, + I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION, + 64); + OUT_BATCH(0); + + ADVANCE_BATCH(); + + intel_batchbuffer_flush(batch); + + drm_intel_bo_map(stats_bo, 0); + stats_result = stats_bo->virtual; + /* skip REPORT_ID, TIMESTAMP */ + stats_result += 3; + for (i = 0 ; i < COUNTER_COUNT; i++) { + totals[i] += stats_result[i] - last_counter[i]; + last_counter[i] = stats_result[i]; + } + + drm_intel_bo_unmap(stats_bo); + drm_intel_bo_unreference(stats_bo); +} + +#define STATS_CHECK_FREQUENCY 100 +#define STATS_REPORT_FREQUENCY 2 + +int +main(int argc, char **argv) +{ + uint32_t devid; + int i; + char clear_screen[] = {0x1b, '[', 'H', + 0x1b, '[', 'J', + 0x0}; + int fd; + int l; + + fd = drm_open_any(); + devid = intel_get_drm_devid(fd); + + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + batch = intel_batchbuffer_alloc(bufmgr, devid); + + if (!IS_GEN5(devid)) { + printf("This tool is only for Ironlake.\n"); + abort(); + } + + for (;;) { + for (l = 0; l < STATS_CHECK_FREQUENCY; l++) { + printf("%s", clear_screen); + + if (l % (STATS_CHECK_FREQUENCY / STATS_REPORT_FREQUENCY) == 0) { + if (have_totals) { + for (i = 0; i < COUNTER_COUNT; i++) { + printf("%s: %u\n", counter_name[i], + totals[i]); + totals[i] = 0; + } + } + } + + get_counters(); + have_totals = 1; + + usleep(1000000 / STATS_CHECK_FREQUENCY); + } + } + + return 0; +}