History

tracing, perf: Convert the power tracer into an event tracer

This patch converts the existing power tracer into an event tracer, so that power events (C states and frequency changes) can be tracked via "perf". This also removes the perl script that was used to demo the tracer; its functionality is being replaced entirely with timechart.

Arjan van de Ven committed 17 years ago

Commit 61613521 parent fd39e0510 files · +113 −388Browse files

Unified · Split

10 files
  1. Documentation/trace/power.txt +0 −17
  2. arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c +2 −5
  3. arch/x86/kernel/process.c +9 −19
  4. include/trace/events/power.h +81 −0
  5. kernel/trace/Makefile +1 −1
  6. kernel/trace/power-traces.c +20 −0
  7. kernel/trace/trace.h +0 −3
  8. kernel/trace/trace_entries.h +0 −17
  9. kernel/trace/trace_power.c +0 −218
  10. scripts/tracing/power.pl +0 −108
Documentation/trace/power.txt+0−17
@@ -1,17 +0,0 @@
1−The power tracer collects detailed information about C-state and P-state
2−transitions, instead of just looking at the high-level "average"
3−information.
4−
5−There is a helper script found in scrips/tracing/power.pl in the kernel
6−sources which can be used to parse this information and create a
7−Scalable Vector Graphics (SVG) picture from the trace data.
8−
9−To use this tracer:
10−
11− echo 0 > /sys/kernel/debug/tracing/tracing_enabled
12− echo power > /sys/kernel/debug/tracing/current_tracer
13− echo 1 > /sys/kernel/debug/tracing/tracing_enabled
14− sleep 1
15− echo 0 > /sys/kernel/debug/tracing/tracing_enabled
16− cat /sys/kernel/debug/tracing/trace | \
17− perl scripts/tracing/power.pl > out.sv
arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c+2−5
@@ -33,7 +33,7 @@ · 32 unmodified lines
3333 #include <linux/cpufreq.h>
3434 #include <linux/compiler.h>
3535 #include <linux/dmi.h>
36−#include <trace/power.h>
36+#include <trace/events/power.h>
3737
3838 #include <linux/acpi.h>
3939 #include <linux/io.h>
@@ -72,8 +72,6 @@ static DEFINE_PER_CPU(struct acpi_cpufreq_data *, drv_data); · 32 unmodified lines
7272
7373 static DEFINE_PER_CPU(struct aperfmperf, old_perf);
7474
75−DEFINE_TRACE(power_mark);
76−
7775 /* acpi_perf_data is a pointer to percpu data. */
7876 static struct acpi_processor_performance *acpi_perf_data;
7977
@@ -332,7 +330,6 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, · 252 unmodified lines
332330 unsigned int next_perf_state = 0; /* Index into perf table */
333331 unsigned int i;
334332 int result = 0;
335− struct power_trace it;
336333
337334 dprintk("acpi_cpufreq_target %d (%d)\n", target_freq, policy->cpu);
338335
@@ -364,7 +361,7 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, · 25 unmodified lines
364361 }
365362 }
366363
367− trace_power_mark(&it, POWER_PSTATE, next_perf_state);
364+ trace_power_frequency(POWER_PSTATE, data->freq_table[next_state].frequency);
368365
369366 switch (data->cpu_feature) {
370367 case SYSTEM_INTEL_MSR_CAPABLE:
arch/x86/kernel/process.c+9−19
@@ -9,7 +9,7 @@ · 8 unmodified lines
99 #include <linux/pm.h>
1010 #include <linux/clockchips.h>
1111 #include <linux/random.h>
12−#include <trace/power.h>
12+#include <trace/events/power.h>
1313 #include <asm/system.h>
1414 #include <asm/apic.h>
1515 #include <asm/syscalls.h>
@@ -25,9 +25,6 @@ EXPORT_SYMBOL(idle_nomwait); · 9 unmodified lines
2525
2626 struct kmem_cache *task_xstate_cachep;
2727
28−DEFINE_TRACE(power_start);
29−DEFINE_TRACE(power_end);
30−
3128 int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
3229 {
3330 *dst = *src;
@@ -299,9 +296,7 @@ static inline int hlt_use_halt(void) · 265 unmodified lines
299296 void default_idle(void)
300297 {
301298 if (hlt_use_halt()) {
302− struct power_trace it;
303−
304− trace_power_start(&it, POWER_CSTATE, 1);
299+ trace_power_start(POWER_CSTATE, 1);
305300 current_thread_info()->status &= ~TS_POLLING;
306301 /*
307302 * TS_POLLING-cleared state must be visible before we
@@ -314,7 +309,7 @@ void default_idle(void) · 6 unmodified lines
314309 else
315310 local_irq_enable();
316311 current_thread_info()->status |= TS_POLLING;
317− trace_power_end(&it);
312+ trace_power_end(0);
318313 } else {
319314 local_irq_enable();
320315 /* loop is done by the caller */
@@ -372,9 +367,7 @@ EXPORT_SYMBOL_GPL(cpu_idle_wait); · 51 unmodified lines
372367 */
373368 void mwait_idle_with_hints(unsigned long ax, unsigned long cx)
374369 {
375− struct power_trace it;
376−
377− trace_power_start(&it, POWER_CSTATE, (ax>>4)+1);
370+ trace_power_start(POWER_CSTATE, (ax>>4)+1);
378371 if (!need_resched()) {
379372 if (cpu_has(&current_cpu_data, X86_FEATURE_CLFLUSH_MONITOR))
380373 clflush((void *)&current_thread_info()->flags);
@@ -384,15 +377,14 @@ void mwait_idle_with_hints(unsigned long ax, unsigned long cx) · 3 unmodified lines
384377 if (!need_resched())
385378 __mwait(ax, cx);
386379 }
387− trace_power_end(&it);
380+ trace_power_end(0);
388381 }
389382
390383 /* Default MONITOR/MWAIT with no hints, used for default C1 state */
391384 static void mwait_idle(void)
392385 {
393− struct power_trace it;
394386 if (!need_resched()) {
395− trace_power_start(&it, POWER_CSTATE, 1);
387+ trace_power_start(POWER_CSTATE, 1);
396388 if (cpu_has(&current_cpu_data, X86_FEATURE_CLFLUSH_MONITOR))
397389 clflush((void *)&current_thread_info()->flags);
398390
@@ -402,7 +394,7 @@ static void mwait_idle(void) · 3 unmodified lines
402394 __sti_mwait(0, 0);
403395 else
404396 local_irq_enable();
405− trace_power_end(&it);
397+ trace_power_end(0);
406398 } else
407399 local_irq_enable();
408400 }
@@ -414,13 +406,11 @@ static void mwait_idle(void) · 5 unmodified lines
414406 */
415407 static void poll_idle(void)
416408 {
417− struct power_trace it;
418−
419− trace_power_start(&it, POWER_CSTATE, 0);
409+ trace_power_start(POWER_CSTATE, 0);
420410 local_irq_enable();
421411 while (!need_resched())
422412 cpu_relax();
423− trace_power_end(&it);
413+ trace_power_end(0);
424414 }
425415
426416 /*
include/trace/events/power.h+81−0
@@ -0,0 +1,81 @@
1+#undef TRACE_SYSTEM
2+#define TRACE_SYSTEM power
3+
4+#if !defined(_TRACE_POWER_H) || defined(TRACE_HEADER_MULTI_READ)
5+#define _TRACE_POWER_H
6+
7+#include <linux/ktime.h>
8+#include <linux/tracepoint.h>
9+
10+#ifndef _TRACE_POWER_ENUM_
11+#define _TRACE_POWER_ENUM_
12+enum {
13+ POWER_NONE = 0,
14+ POWER_CSTATE = 1,
15+ POWER_PSTATE = 2,
16+};
17+#endif
18+
19+
20+
21+TRACE_EVENT(power_start,
22+
23+ TP_PROTO(unsigned int type, unsigned int state),
24+
25+ TP_ARGS(type, state),
26+
27+ TP_STRUCT__entry(
28+ __field( u64, type )
29+ __field( u64, state )
30+ ),
31+
32+ TP_fast_assign(
33+ __entry->type = type;
34+ __entry->state = state;
35+ ),
36+
37+ TP_printk("type=%lu state=%lu", (unsigned long)__entry->type, (unsigned long)__entry->state)
38+);
39+
40+TRACE_EVENT(power_end,
41+
42+ TP_PROTO(int dummy),
43+
44+ TP_ARGS(dummy),
45+
46+ TP_STRUCT__entry(
47+ __field( u64, dummy )
48+ ),
49+
50+ TP_fast_assign(
51+ __entry->dummy = 0xffff;
52+ ),
53+
54+ TP_printk("dummy=%lu", (unsigned long)__entry->dummy)
55+
56+);
57+
58+
59+TRACE_EVENT(power_frequency,
60+
61+ TP_PROTO(unsigned int type, unsigned int state),
62+
63+ TP_ARGS(type, state),
64+
65+ TP_STRUCT__entry(
66+ __field( u64, type )
67+ __field( u64, state )
68+ ),
69+
70+ TP_fast_assign(
71+ __entry->type = type;
72+ __entry->state = state;
73+ ),
74+
75+ TP_printk("type=%lu state=%lu", (unsigned long)__entry->type, (unsigned long) __entry->state)
76+);
77+
78+#endif /* _TRACE_POWER_H */
79+
80+/* This part must be outside protection */
81+#include <trace/define_trace.h>
kernel/trace/Makefile+1−1
@@ -42,7 +42,6 @@ obj-$(CONFIG_BOOT_TRACER) += trace_boot.o · 41 unmodified lines
4242 obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += trace_functions_graph.o
4343 obj-$(CONFIG_TRACE_BRANCH_PROFILING) += trace_branch.o
4444 obj-$(CONFIG_HW_BRANCH_TRACER) += trace_hw_branches.o
45−obj-$(CONFIG_POWER_TRACER) += trace_power.o
4645 obj-$(CONFIG_KMEMTRACE) += kmemtrace.o
4746 obj-$(CONFIG_WORKQUEUE_TRACER) += trace_workqueue.o
4847 obj-$(CONFIG_BLK_DEV_IO_TRACE) += blktrace.o
@@ -54,5 +53,6 @@ obj-$(CONFIG_EVENT_TRACING) += trace_export.o · 5 unmodified lines
5453 obj-$(CONFIG_FTRACE_SYSCALLS) += trace_syscalls.o
5554 obj-$(CONFIG_EVENT_PROFILE) += trace_event_profile.o
5655 obj-$(CONFIG_EVENT_TRACING) += trace_events_filter.o
56+obj-$(CONFIG_EVENT_TRACING) += power-traces.o
5757
5858 libftrace-y := ftrace.o
kernel/trace/power-traces.c+20−0
@@ -0,0 +1,20 @@
1+/*
2+ * Power trace points
3+ *
4+ * Copyright (C) 2009 Arjan van de Ven <arjan@linux.intel.com>
5+ */
6+
7+#include <linux/string.h>
8+#include <linux/types.h>
9+#include <linux/workqueue.h>
10+#include <linux/sched.h>
11+#include <linux/module.h>
12+#include <linux/slab.h>
13+
14+#define CREATE_TRACE_POINTS
15+#include <trace/events/power.h>
16+
17+EXPORT_TRACEPOINT_SYMBOL_GPL(power_start);
18+EXPORT_TRACEPOINT_SYMBOL_GPL(power_end);
19+EXPORT_TRACEPOINT_SYMBOL_GPL(power_frequency);
20+
kernel/trace/trace.h+0−3
@@ -11,7 +11,6 @@ · 10 unmodified lines
1111 #include <linux/ftrace.h>
1212 #include <trace/boot.h>
1313 #include <linux/kmemtrace.h>
14−#include <trace/power.h>
1514
1615 #include <linux/trace_seq.h>
1716 #include <linux/ftrace_event.h>
@@ -37,7 +36,6 @@ enum trace_type { · 19 unmodified lines
3736 TRACE_HW_BRANCHES,
3837 TRACE_KMEM_ALLOC,
3938 TRACE_KMEM_FREE,
40− TRACE_POWER,
4139 TRACE_BLK,
4240
4341 __TRACE_LAST_TYPE,
@@ -207,7 +205,6 @@ extern void __ftrace_bad_type(void); · 163 unmodified lines
207205 IF_ASSIGN(var, ent, struct ftrace_graph_ret_entry, \
208206 TRACE_GRAPH_RET); \
209207 IF_ASSIGN(var, ent, struct hw_branch_entry, TRACE_HW_BRANCHES);\
210− IF_ASSIGN(var, ent, struct trace_power, TRACE_POWER); \
211208 IF_ASSIGN(var, ent, struct kmemtrace_alloc_entry, \
212209 TRACE_KMEM_ALLOC); \
213210 IF_ASSIGN(var, ent, struct kmemtrace_free_entry, \
kernel/trace/trace_entries.h+0−17
@@ -330,23 +330,6 @@ FTRACE_ENTRY(hw_branch, hw_branch_entry, · 329 unmodified lines
330330 F_printk("from: %llx to: %llx", __entry->from, __entry->to)
331331 );
332332
333−FTRACE_ENTRY(power, trace_power,
334−
335− TRACE_POWER,
336−
337− F_STRUCT(
338− __field_struct( struct power_trace, state_data )
339− __field_desc( s64, state_data, stamp )
340− __field_desc( s64, state_data, end )
341− __field_desc( int, state_data, type )
342− __field_desc( int, state_data, state )
343− ),
344−
345− F_printk("%llx->%llx type:%u state:%u",
346− __entry->stamp, __entry->end,
347− __entry->type, __entry->state)
348−);
349−
350333 FTRACE_ENTRY(kmem_alloc, kmemtrace_alloc_entry,
351334
352335 TRACE_KMEM_ALLOC,
kernel/trace/trace_power.c+0−218
@@ -1,218 +0,0 @@
1−/*
2− * ring buffer based C-state tracer
3− *
4− * Arjan van de Ven <arjan@linux.intel.com>
5− * Copyright (C) 2008 Intel Corporation
6− *
7− * Much is borrowed from trace_boot.c which is
8− * Copyright (C) 2008 Frederic Weisbecker <fweisbec@gmail.com>
9− *
10− */
11−
12−#include <linux/init.h>
13−#include <linux/debugfs.h>
14−#include <trace/power.h>
15−#include <linux/kallsyms.h>
16−#include <linux/module.h>
17−
18−#include "trace.h"
19−#include "trace_output.h"
20−
21−static struct trace_array *power_trace;
22−static int __read_mostly trace_power_enabled;
23−
24−static void probe_power_start(struct power_trace *it, unsigned int type,
25− unsigned int level)
26−{
27− if (!trace_power_enabled)
28− return;
29−
30− memset(it, 0, sizeof(struct power_trace));
31− it->state = level;
32− it->type = type;
33− it->stamp = ktime_get();
34−}
35−
36−
37−static void probe_power_end(struct power_trace *it)
38−{
39− struct ftrace_event_call *call = &event_power;
40− struct ring_buffer_event *event;
41− struct ring_buffer *buffer;
42− struct trace_power *entry;
43− struct trace_array_cpu *data;
44− struct trace_array *tr = power_trace;
45−
46− if (!trace_power_enabled)
47− return;
48−
49− buffer = tr->buffer;
50−
51− preempt_disable();
52− it->end = ktime_get();
53− data = tr->data[smp_processor_id()];
54−
55− event = trace_buffer_lock_reserve(buffer, TRACE_POWER,
56− sizeof(*entry), 0, 0);
57− if (!event)
58− goto out;
59− entry = ring_buffer_event_data(event);
60− entry->state_data = *it;
61− if (!filter_check_discard(call, entry, buffer, event))
62− trace_buffer_unlock_commit(buffer, event, 0, 0);
63− out:
64− preempt_enable();
65−}
66−
67−static void probe_power_mark(struct power_trace *it, unsigned int type,
68− unsigned int level)
69−{
70− struct ftrace_event_call *call = &event_power;
71− struct ring_buffer_event *event;
72− struct ring_buffer *buffer;
73− struct trace_power *entry;
74− struct trace_array_cpu *data;
75− struct trace_array *tr = power_trace;
76−
77− if (!trace_power_enabled)
78− return;
79−
80− buffer = tr->buffer;
81−
82− memset(it, 0, sizeof(struct power_trace));
83− it->state = level;
84− it->type = type;
85− it->stamp = ktime_get();
86− preempt_disable();
87− it->end = it->stamp;
88− data = tr->data[smp_processor_id()];
89−
90− event = trace_buffer_lock_reserve(buffer, TRACE_POWER,
91− sizeof(*entry), 0, 0);
92− if (!event)
93− goto out;
94− entry = ring_buffer_event_data(event);
95− entry->state_data = *it;
96− if (!filter_check_discard(call, entry, buffer, event))
97− trace_buffer_unlock_commit(buffer, event, 0, 0);
98− out:
99− preempt_enable();
100−}
101−
102−static int tracing_power_register(void)
103−{
104− int ret;
105−
106− ret = register_trace_power_start(probe_power_start);
107− if (ret) {
108− pr_info("power trace: Couldn't activate tracepoint"
109− " probe to trace_power_start\n");
110− return ret;
111− }
112− ret = register_trace_power_end(probe_power_end);
113− if (ret) {
114− pr_info("power trace: Couldn't activate tracepoint"
115− " probe to trace_power_end\n");
116− goto fail_start;
117− }
118− ret = register_trace_power_mark(probe_power_mark);
119− if (ret) {
120− pr_info("power trace: Couldn't activate tracepoint"
121− " probe to trace_power_mark\n");
122− goto fail_end;
123− }
124− return ret;
125−fail_end:
126− unregister_trace_power_end(probe_power_end);
127−fail_start:
128− unregister_trace_power_start(probe_power_start);
129− return ret;
130−}
131−
132−static void start_power_trace(struct trace_array *tr)
133−{
134− trace_power_enabled = 1;
135−}
136−
137−static void stop_power_trace(struct trace_array *tr)
138−{
139− trace_power_enabled = 0;
140−}
141−
142−static void power_trace_reset(struct trace_array *tr)
143−{
144− trace_power_enabled = 0;
145− unregister_trace_power_start(probe_power_start);
146− unregister_trace_power_end(probe_power_end);
147− unregister_trace_power_mark(probe_power_mark);
148−}
149−
150−
151−static int power_trace_init(struct trace_array *tr)
152−{
153− power_trace = tr;
154−
155− trace_power_enabled = 1;
156− tracing_power_register();
157−
158− tracing_reset_online_cpus(tr);
159− return 0;
160−}
161−
162−static enum print_line_t power_print_line(struct trace_iterator *iter)
163−{
164− int ret = 0;
165− struct trace_entry *entry = iter->ent;
166− struct trace_power *field ;
167− struct power_trace *it;
168− struct trace_seq *s = &iter->seq;
169− struct timespec stamp;
170− struct timespec duration;
171−
172− trace_assign_type(field, entry);
173− it = &field->state_data;
174− stamp = ktime_to_timespec(it->stamp);
175− duration = ktime_to_timespec(ktime_sub(it->end, it->stamp));
176−
177− if (entry->type == TRACE_POWER) {
178− if (it->type == POWER_CSTATE)
179− ret = trace_seq_printf(s, "[%5ld.%09ld] CSTATE: Going to C%i on cpu %i for %ld.%09ld\n",
180− stamp.tv_sec,
181− stamp.tv_nsec,
182− it->state, iter->cpu,
183− duration.tv_sec,
184− duration.tv_nsec);
185− if (it->type == POWER_PSTATE)
186− ret = trace_seq_printf(s, "[%5ld.%09ld] PSTATE: Going to P%i on cpu %i\n",
187− stamp.tv_sec,
188− stamp.tv_nsec,
189− it->state, iter->cpu);
190− if (!ret)
191− return TRACE_TYPE_PARTIAL_LINE;
192− return TRACE_TYPE_HANDLED;
193− }
194− return TRACE_TYPE_UNHANDLED;
195−}
196−
197−static void power_print_header(struct seq_file *s)
198−{
199− seq_puts(s, "# TIMESTAMP STATE EVENT\n");
200− seq_puts(s, "# | | |\n");
201−}
202−
203−static struct tracer power_tracer __read_mostly =
204−{
205− .name = "power",
206− .init = power_trace_init,
207− .start = start_power_trace,
208− .stop = stop_power_trace,
209− .reset = power_trace_reset,
210− .print_line = power_print_line,
211− .print_header = power_print_header,
212−};
213−
214−static int init_power_trace(void)
215−{
216− return register_tracer(&power_tracer);
217−}
218−device_initcall(init_power_trace);
scripts/tracing/power.pl+0−108
@@ -1,108 +0,0 @@
1−#!/usr/bin/perl
2−
3−# Copyright 2008, Intel Corporation
4−#
5−# This file is part of the Linux kernel
6−#
7−# This program file is free software; you can redistribute it and/or modify it
8−# under the terms of the GNU General Public License as published by the
9−# Free Software Foundation; version 2 of the License.
10−#
11−# This program is distributed in the hope that it will be useful, but WITHOUT
12−# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13−# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14−# for more details.
15−#
16−# You should have received a copy of the GNU General Public License
17−# along with this program in a file named COPYING; if not, write to the
18−# Free Software Foundation, Inc.,
19−# 51 Franklin Street, Fifth Floor,
20−# Boston, MA 02110-1301 USA
21−#
22−# Authors:
23−# Arjan van de Ven <arjan@linux.intel.com>
24−
25−
26−#
27−# This script turns a cstate ftrace output into a SVG graphic that shows
28−# historic C-state information
29−#
30−#
31−# cat /sys/kernel/debug/tracing/trace | perl power.pl > out.svg
32−#
33−
34−my @styles;
35−my $base = 0;
36−
37−my @pstate_last;
38−my @pstate_level;
39−
40−$styles[0] = "fill:rgb(0,0,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
41−$styles[1] = "fill:rgb(0,255,0);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
42−$styles[2] = "fill:rgb(255,0,20);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
43−$styles[3] = "fill:rgb(255,255,20);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
44−$styles[4] = "fill:rgb(255,0,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
45−$styles[5] = "fill:rgb(0,255,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
46−$styles[6] = "fill:rgb(0,128,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
47−$styles[7] = "fill:rgb(0,255,128);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
48−$styles[8] = "fill:rgb(0,25,20);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
49−
50−
51−print "<?xml version=\"1.0\" standalone=\"no\"?> \n";
52−print "<svg width=\"10000\" height=\"100%\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n";
53−
54−my $scale = 30000.0;
55−while (<>) {
56− my $line = $_;
57− if ($line =~ /([0-9\.]+)\] CSTATE: Going to C([0-9]) on cpu ([0-9]+) for ([0-9\.]+)/) {
58− if ($base == 0) {
59− $base = $1;
60− }
61− my $time = $1 - $base;
62− $time = $time * $scale;
63− my $C = $2;
64− my $cpu = $3;
65− my $y = 400 * $cpu;
66− my $duration = $4 * $scale;
67− my $msec = int($4 * 100000)/100.0;
68− my $height = $C * 20;
69− $style = $styles[$C];
70−
71− $y = $y + 140 - $height;
72−
73− $x2 = $time + 4;
74− $y2 = $y + 4;
75−
76−
77− print "<rect x=\"$time\" width=\"$duration\" y=\"$y\" height=\"$height\" style=\"$style\"/>\n";
78− print "<text transform=\"translate($x2,$y2) rotate(90)\">C$C $msec</text>\n";
79− }
80− if ($line =~ /([0-9\.]+)\] PSTATE: Going to P([0-9]) on cpu ([0-9]+)/) {
81− my $time = $1 - $base;
82− my $state = $2;
83− my $cpu = $3;
84−
85− if (defined($pstate_last[$cpu])) {
86− my $from = $pstate_last[$cpu];
87− my $oldstate = $pstate_state[$cpu];
88− my $duration = ($time-$from) * $scale;
89−
90− $from = $from * $scale;
91− my $to = $from + $duration;
92− my $height = 140 - ($oldstate * (140/8));
93−
94− my $y = 400 * $cpu + 200 + $height;
95− my $y2 = $y+4;
96− my $style = $styles[8];
97−
98− print "<rect x=\"$from\" y=\"$y\" width=\"$duration\" height=\"5\" style=\"$style\"/>\n";
99− print "<text transform=\"translate($from,$y2)\">P$oldstate (cpu $cpu)</text>\n";
100− };
101−
102− $pstate_last[$cpu] = $time;
103− $pstate_state[$cpu] = $state;
104− }
105−}
106−
107−
108−print "</svg>\n";