aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Brown2014-08-22 13:33:17 -0500
committerMark Brown2014-08-22 13:33:17 -0500
commitc27744f4eb311589f693e9c67c7f778b77f89d26 (patch)
treeb8a013d826f85ab7737b338d6e5b4e7eab3c3ea3
parent586197edd648635f892870b1c4f726496a8dcb6c (diff)
parent43bc6d5b076e30d55b59daedeb205063cb6e54a2 (diff)
downloadkernel-video-c27744f4eb311589f693e9c67c7f778b77f89d26.tar.gz
kernel-video-c27744f4eb311589f693e9c67c7f778b77f89d26.tar.xz
kernel-video-c27744f4eb311589f693e9c67c7f778b77f89d26.zip
Merge remote-tracking branch 'lsk/v3.14/topic/gator' into linux-linaro-lsk-v3.14
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/gator/Kconfig38
-rw-r--r--drivers/gator/LICENSE339
-rw-r--r--drivers/gator/Makefile81
-rw-r--r--drivers/gator/gator.h149
-rw-r--r--drivers/gator/gator_annotate.c186
-rw-r--r--drivers/gator/gator_annotate_kernel.c202
-rw-r--r--drivers/gator/gator_backtrace.c208
-rw-r--r--drivers/gator/gator_buffer.c168
-rw-r--r--drivers/gator/gator_buffer_write.c80
-rw-r--r--drivers/gator/gator_cookies.c437
-rw-r--r--drivers/gator/gator_events_armv6.c237
-rw-r--r--drivers/gator/gator_events_armv7.c314
-rw-r--r--drivers/gator/gator_events_block.c163
-rw-r--r--drivers/gator/gator_events_ccn-504.c346
-rw-r--r--drivers/gator/gator_events_irq.c165
-rw-r--r--drivers/gator/gator_events_l2c-310.c208
-rw-r--r--drivers/gator/gator_events_mali_4xx.c669
-rw-r--r--drivers/gator/gator_events_mali_4xx.h18
-rw-r--r--drivers/gator/gator_events_mali_common.c69
-rw-r--r--drivers/gator/gator_events_mali_common.h78
-rw-r--r--drivers/gator/gator_events_mali_t6xx.c567
-rw-r--r--drivers/gator/gator_events_mali_t6xx_hw.c913
-rw-r--r--drivers/gator/gator_events_mali_t6xx_hw_test.c55
-rw-r--r--drivers/gator/gator_events_meminfo.c409
-rw-r--r--drivers/gator/gator_events_mmapped.c209
-rw-r--r--drivers/gator/gator_events_net.c172
-rw-r--r--drivers/gator/gator_events_perf_pmu.c587
-rw-r--r--drivers/gator/gator_events_sched.c113
-rw-r--r--drivers/gator/gator_events_scorpion.c669
-rw-r--r--drivers/gator/gator_events_threads.c115
-rw-r--r--drivers/gator/gator_fs.c365
-rw-r--r--drivers/gator/gator_hrtimer_gator.c80
-rw-r--r--drivers/gator/gator_iks.c197
-rw-r--r--drivers/gator/gator_main.c1460
-rw-r--r--drivers/gator/gator_marshaling.c362
-rw-r--r--drivers/gator/gator_trace_gpu.c333
-rw-r--r--drivers/gator/gator_trace_power.c203
-rw-r--r--drivers/gator/gator_trace_sched.c297
-rw-r--r--drivers/gator/mali/mali_dd_gator_api.h40
-rw-r--r--drivers/gator/mali/mali_mjollnir_profiling_gator_api.h163
-rw-r--r--drivers/gator/mali/mali_utgard_profiling_gator_api.h201
-rw-r--r--drivers/gator/mali_t6xx.mk39
-rw-r--r--tools/gator/daemon/Android.mk65
-rw-r--r--tools/gator/daemon/Application.mk1
-rw-r--r--tools/gator/daemon/Buffer.cpp391
-rw-r--r--tools/gator/daemon/Buffer.h102
-rw-r--r--tools/gator/daemon/CapturedXML.cpp144
-rw-r--r--tools/gator/daemon/CapturedXML.h26
-rw-r--r--tools/gator/daemon/Child.cpp346
-rw-r--r--tools/gator/daemon/Child.h33
-rw-r--r--tools/gator/daemon/Config.h17
-rw-r--r--tools/gator/daemon/ConfigurationXML.cpp217
-rw-r--r--tools/gator/daemon/ConfigurationXML.h38
-rw-r--r--tools/gator/daemon/Counter.h65
-rw-r--r--tools/gator/daemon/Driver.cpp15
-rw-r--r--tools/gator/daemon/Driver.h48
-rw-r--r--tools/gator/daemon/DriverSource.cpp321
-rw-r--r--tools/gator/daemon/DriverSource.h57
-rw-r--r--tools/gator/daemon/DynBuf.cpp139
-rw-r--r--tools/gator/daemon/DynBuf.h52
-rw-r--r--tools/gator/daemon/EventsXML.cpp76
-rw-r--r--tools/gator/daemon/EventsXML.h21
-rw-r--r--tools/gator/daemon/ExternalSource.cpp215
-rw-r--r--tools/gator/daemon/ExternalSource.h49
-rw-r--r--tools/gator/daemon/FSDriver.cpp212
-rw-r--r--tools/gator/daemon/FSDriver.h44
-rw-r--r--tools/gator/daemon/Fifo.cpp130
-rw-r--r--tools/gator/daemon/Fifo.h48
-rw-r--r--tools/gator/daemon/Hwmon.cpp352
-rw-r--r--tools/gator/daemon/Hwmon.h45
-rw-r--r--tools/gator/daemon/KMod.cpp110
-rw-r--r--tools/gator/daemon/KMod.h27
-rw-r--r--tools/gator/daemon/LocalCapture.cpp131
-rw-r--r--tools/gator/daemon/LocalCapture.h26
-rw-r--r--tools/gator/daemon/Logging.cpp78
-rw-r--r--tools/gator/daemon/Logging.h36
-rw-r--r--tools/gator/daemon/Makefile25
-rw-r--r--tools/gator/daemon/Makefile_aarch6412
-rw-r--r--tools/gator/daemon/MaliVideoDriver.cpp253
-rw-r--r--tools/gator/daemon/MaliVideoDriver.h50
-rw-r--r--tools/gator/daemon/Monitor.cpp68
-rw-r--r--tools/gator/daemon/Monitor.h33
-rw-r--r--tools/gator/daemon/OlySocket.cpp282
-rw-r--r--tools/gator/daemon/OlySocket.h55
-rw-r--r--tools/gator/daemon/OlyUtility.cpp227
-rw-r--r--tools/gator/daemon/OlyUtility.h42
-rw-r--r--tools/gator/daemon/PerfBuffer.cpp139
-rw-r--r--tools/gator/daemon/PerfBuffer.h39
-rw-r--r--tools/gator/daemon/PerfDriver.cpp409
-rw-r--r--tools/gator/daemon/PerfDriver.h60
-rw-r--r--tools/gator/daemon/PerfGroup.cpp226
-rw-r--r--tools/gator/daemon/PerfGroup.h57
-rw-r--r--tools/gator/daemon/PerfSource.cpp275
-rw-r--r--tools/gator/daemon/PerfSource.h54
-rw-r--r--tools/gator/daemon/Proc.cpp215
-rw-r--r--tools/gator/daemon/Proc.h17
-rw-r--r--tools/gator/daemon/Sender.cpp134
-rw-r--r--tools/gator/daemon/Sender.h42
-rw-r--r--tools/gator/daemon/SessionData.cpp194
-rw-r--r--tools/gator/daemon/SessionData.h86
-rw-r--r--tools/gator/daemon/SessionXML.cpp111
-rw-r--r--tools/gator/daemon/SessionXML.h42
-rw-r--r--tools/gator/daemon/Source.cpp33
-rw-r--r--tools/gator/daemon/Source.h40
-rw-r--r--tools/gator/daemon/StreamlineSetup.cpp272
-rw-r--r--tools/gator/daemon/StreamlineSetup.h50
-rw-r--r--tools/gator/daemon/UEvent.cpp76
-rw-r--r--tools/gator/daemon/UEvent.h36
-rw-r--r--tools/gator/daemon/UserSpaceSource.cpp89
-rw-r--r--tools/gator/daemon/UserSpaceSource.h38
-rw-r--r--tools/gator/daemon/c++.cpp40
-rw-r--r--tools/gator/daemon/common.mk52
-rw-r--r--tools/gator/daemon/defaults.xml67
-rw-r--r--tools/gator/daemon/escape.c75
-rw-r--r--tools/gator/daemon/events-ARM11.xml39
-rw-r--r--tools/gator/daemon/events-ARM11MPCore.xml26
-rw-r--r--tools/gator/daemon/events-CCI-400.xml98
-rw-r--r--tools/gator/daemon/events-CCN-504.xml113
-rw-r--r--tools/gator/daemon/events-Cortex-A12.xml86
-rw-r--r--tools/gator/daemon/events-Cortex-A15.xml68
-rw-r--r--tools/gator/daemon/events-Cortex-A5.xml36
-rw-r--r--tools/gator/daemon/events-Cortex-A53.xml87
-rw-r--r--tools/gator/daemon/events-Cortex-A57.xml87
-rw-r--r--tools/gator/daemon/events-Cortex-A7.xml43
-rw-r--r--tools/gator/daemon/events-Cortex-A8.xml52
-rw-r--r--tools/gator/daemon/events-Cortex-A9.xml65
-rw-r--r--tools/gator/daemon/events-Filesystem.xml11
-rw-r--r--tools/gator/daemon/events-Krait-architected.xml22
-rw-r--r--tools/gator/daemon/events-L2C-310.xml18
-rw-r--r--tools/gator/daemon/events-Linux.xml16
-rw-r--r--tools/gator/daemon/events-Mali-4xx.xml245
-rw-r--r--tools/gator/daemon/events-Mali-T6xx.xml46
-rw-r--r--tools/gator/daemon/events-Mali-T6xx_hw.xml91
-rw-r--r--tools/gator/daemon/events-Mali-V500.xml29
-rw-r--r--tools/gator/daemon/events-Perf-Hardware.xml12
-rw-r--r--tools/gator/daemon/events-Scorpion.xml107
-rw-r--r--tools/gator/daemon/events-ScorpionMP.xml90
-rw-r--r--tools/gator/daemon/events_footer.xml1
-rw-r--r--tools/gator/daemon/events_header.xml2
-rw-r--r--tools/gator/daemon/k/perf_event.3.12.h792
l---------tools/gator/daemon/k/perf_event.h1
-rw-r--r--tools/gator/daemon/libsensors/COPYING.LGPL502
-rw-r--r--tools/gator/daemon/libsensors/access.c561
-rw-r--r--tools/gator/daemon/libsensors/access.h33
-rw-r--r--tools/gator/daemon/libsensors/conf-lex.c2881
-rw-r--r--tools/gator/daemon/libsensors/conf-lex.l372
-rw-r--r--tools/gator/daemon/libsensors/conf-parse.c2042
-rw-r--r--tools/gator/daemon/libsensors/conf-parse.h84
-rw-r--r--tools/gator/daemon/libsensors/conf-parse.y347
-rw-r--r--tools/gator/daemon/libsensors/conf.h34
-rw-r--r--tools/gator/daemon/libsensors/data.c278
-rw-r--r--tools/gator/daemon/libsensors/data.h184
-rw-r--r--tools/gator/daemon/libsensors/error.c92
-rw-r--r--tools/gator/daemon/libsensors/error.h74
-rw-r--r--tools/gator/daemon/libsensors/general.c85
-rw-r--r--tools/gator/daemon/libsensors/general.h39
-rw-r--r--tools/gator/daemon/libsensors/init.c341
-rw-r--r--tools/gator/daemon/libsensors/init.h28
-rw-r--r--tools/gator/daemon/libsensors/scanner.h32
-rw-r--r--tools/gator/daemon/libsensors/sensors.h311
-rw-r--r--tools/gator/daemon/libsensors/sysfs.c926
-rw-r--r--tools/gator/daemon/libsensors/sysfs.h43
-rw-r--r--tools/gator/daemon/libsensors/version.h1
-rw-r--r--tools/gator/daemon/main.cpp547
-rw-r--r--tools/gator/daemon/mxml/COPYING507
-rw-r--r--tools/gator/daemon/mxml/config.h96
-rw-r--r--tools/gator/daemon/mxml/mxml-attr.c319
-rw-r--r--tools/gator/daemon/mxml/mxml-entity.c460
-rw-r--r--tools/gator/daemon/mxml/mxml-file.c3082
-rw-r--r--tools/gator/daemon/mxml/mxml-get.c471
-rw-r--r--tools/gator/daemon/mxml/mxml-index.c662
-rw-r--r--tools/gator/daemon/mxml/mxml-node.c807
-rw-r--r--tools/gator/daemon/mxml/mxml-private.c331
-rw-r--r--tools/gator/daemon/mxml/mxml-private.h50
-rw-r--r--tools/gator/daemon/mxml/mxml-search.c287
-rw-r--r--tools/gator/daemon/mxml/mxml-set.c349
-rw-r--r--tools/gator/daemon/mxml/mxml-string.c476
-rw-r--r--tools/gator/daemon/mxml/mxml.h329
180 files changed, 39746 insertions, 0 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index b3138fbb46a..c1e4021f436 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -170,4 +170,6 @@ source "drivers/phy/Kconfig"
170 170
171source "drivers/powercap/Kconfig" 171source "drivers/powercap/Kconfig"
172 172
173source "drivers/gator/Kconfig"
174
173endmenu 175endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 8e3b8b06c0b..7edd884f2b5 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -155,3 +155,5 @@ obj-$(CONFIG_IPACK_BUS) += ipack/
155obj-$(CONFIG_NTB) += ntb/ 155obj-$(CONFIG_NTB) += ntb/
156obj-$(CONFIG_FMC) += fmc/ 156obj-$(CONFIG_FMC) += fmc/
157obj-$(CONFIG_POWERCAP) += powercap/ 157obj-$(CONFIG_POWERCAP) += powercap/
158
159obj-$(CONFIG_GATOR) += gator/
diff --git a/drivers/gator/Kconfig b/drivers/gator/Kconfig
new file mode 100644
index 00000000000..31f0c6fb8ba
--- /dev/null
+++ b/drivers/gator/Kconfig
@@ -0,0 +1,38 @@
1config GATOR
2 tristate "Gator module for ARM's Streamline Performance Analyzer"
3 default m if (ARM || ARM64)
4 depends on PROFILING
5 depends on HIGH_RES_TIMERS
6 depends on PERF_EVENTS
7 depends on HW_PERF_EVENTS || !(ARM || ARM64)
8 select TRACING
9 help
10 Gator module for ARM's Streamline Performance Analyzer
11
12config GATOR_WITH_MALI_SUPPORT
13 bool
14
15choice
16 prompt "Enable Mali GPU support in Gator"
17 depends on GATOR
18 optional
19 help
20 Enable Mali GPU support in Gator
21
22config GATOR_MALI_4XXMP
23 bool "Mali-400MP or Mali-450MP"
24 select GATOR_WITH_MALI_SUPPORT
25
26config GATOR_MALI_T6XX
27 bool "Mali-T604 or Mali-T658"
28 select GATOR_WITH_MALI_SUPPORT
29
30endchoice
31
32config GATOR_MALI_PATH
33 string "Path to Mali driver"
34 depends on GATOR_WITH_MALI_SUPPORT
35 default "drivers/gpu/arm/mali400mp"
36 help
37 The gator code adds this to its include path so it can get the Mali
38 trace headers with: #include "linux/mali_linux_trace.h"
diff --git a/drivers/gator/LICENSE b/drivers/gator/LICENSE
new file mode 100644
index 00000000000..d159169d105
--- /dev/null
+++ b/drivers/gator/LICENSE
@@ -0,0 +1,339 @@
1 GNU GENERAL PUBLIC LICENSE
2 Version 2, June 1991
3
4 Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 Everyone is permitted to copy and distribute verbatim copies
7 of this license document, but changing it is not allowed.
8
9 Preamble
10
11 The licenses for most software are designed to take away your
12freedom to share and change it. By contrast, the GNU General Public
13License is intended to guarantee your freedom to share and change free
14software--to make sure the software is free for all its users. This
15General Public License applies to most of the Free Software
16Foundation's software and to any other program whose authors commit to
17using it. (Some other Free Software Foundation software is covered by
18the GNU Lesser General Public License instead.) You can apply it to
19your programs, too.
20
21 When we speak of free software, we are referring to freedom, not
22price. Our General Public Licenses are designed to make sure that you
23have the freedom to distribute copies of free software (and charge for
24this service if you wish), that you receive source code or can get it
25if you want it, that you can change the software or use pieces of it
26in new free programs; and that you know you can do these things.
27
28 To protect your rights, we need to make restrictions that forbid
29anyone to deny you these rights or to ask you to surrender the rights.
30These restrictions translate to certain responsibilities for you if you
31distribute copies of the software, or if you modify it.
32
33 For example, if you distribute copies of such a program, whether
34gratis or for a fee, you must give the recipients all the rights that
35you have. You must make sure that they, too, receive or can get the
36source code. And you must show them these terms so they know their
37rights.
38
39 We protect your rights with two steps: (1) copyright the software, and
40(2) offer you this license which gives you legal permission to copy,
41distribute and/or modify the software.
42
43 Also, for each author's protection and ours, we want to make certain
44that everyone understands that there is no warranty for this free
45software. If the software is modified by someone else and passed on, we
46want its recipients to know that what they have is not the original, so
47that any problems introduced by others will not reflect on the original
48authors' reputations.
49
50 Finally, any free program is threatened constantly by software
51patents. We wish to avoid the danger that redistributors of a free
52program will individually obtain patent licenses, in effect making the
53program proprietary. To prevent this, we have made it clear that any
54patent must be licensed for everyone's free use or not licensed at all.
55
56 The precise terms and conditions for copying, distribution and
57modification follow.
58
59 GNU GENERAL PUBLIC LICENSE
60 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61
62 0. This License applies to any program or other work which contains
63a notice placed by the copyright holder saying it may be distributed
64under the terms of this General Public License. The "Program", below,
65refers to any such program or work, and a "work based on the Program"
66means either the Program or any derivative work under copyright law:
67that is to say, a work containing the Program or a portion of it,
68either verbatim or with modifications and/or translated into another
69language. (Hereinafter, translation is included without limitation in
70the term "modification".) Each licensee is addressed as "you".
71
72Activities other than copying, distribution and modification are not
73covered by this License; they are outside its scope. The act of
74running the Program is not restricted, and the output from the Program
75is covered only if its contents constitute a work based on the
76Program (independent of having been made by running the Program).
77Whether that is true depends on what the Program does.
78
79 1. You may copy and distribute verbatim copies of the Program's
80source code as you receive it, in any medium, provided that you
81conspicuously and appropriately publish on each copy an appropriate
82copyright notice and disclaimer of warranty; keep intact all the
83notices that refer to this License and to the absence of any warranty;
84and give any other recipients of the Program a copy of this License
85along with the Program.
86
87You may charge a fee for the physical act of transferring a copy, and
88you may at your option offer warranty protection in exchange for a fee.
89
90 2. You may modify your copy or copies of the Program or any portion
91of it, thus forming a work based on the Program, and copy and
92distribute such modifications or work under the terms of Section 1
93above, provided that you also meet all of these conditions:
94
95 a) You must cause the modified files to carry prominent notices
96 stating that you changed the files and the date of any change.
97
98 b) You must cause any work that you distribute or publish, that in
99 whole or in part contains or is derived from the Program or any
100 part thereof, to be licensed as a whole at no charge to all third
101 parties under the terms of this License.
102
103 c) If the modified program normally reads commands interactively
104 when run, you must cause it, when started running for such
105 interactive use in the most ordinary way, to print or display an
106 announcement including an appropriate copyright notice and a
107 notice that there is no warranty (or else, saying that you provide
108 a warranty) and that users may redistribute the program under
109 these conditions, and telling the user how to view a copy of this
110 License. (Exception: if the Program itself is interactive but
111 does not normally print such an announcement, your work based on
112 the Program is not required to print an announcement.)
113
114These requirements apply to the modified work as a whole. If
115identifiable sections of that work are not derived from the Program,
116and can be reasonably considered independent and separate works in
117themselves, then this License, and its terms, do not apply to those
118sections when you distribute them as separate works. But when you
119distribute the same sections as part of a whole which is a work based
120on the Program, the distribution of the whole must be on the terms of
121this License, whose permissions for other licensees extend to the
122entire whole, and thus to each and every part regardless of who wrote it.
123
124Thus, it is not the intent of this section to claim rights or contest
125your rights to work written entirely by you; rather, the intent is to
126exercise the right to control the distribution of derivative or
127collective works based on the Program.
128
129In addition, mere aggregation of another work not based on the Program
130with the Program (or with a work based on the Program) on a volume of
131a storage or distribution medium does not bring the other work under
132the scope of this License.
133
134 3. You may copy and distribute the Program (or a work based on it,
135under Section 2) in object code or executable form under the terms of
136Sections 1 and 2 above provided that you also do one of the following:
137
138 a) Accompany it with the complete corresponding machine-readable
139 source code, which must be distributed under the terms of Sections
140 1 and 2 above on a medium customarily used for software interchange; or,
141
142 b) Accompany it with a written offer, valid for at least three
143 years, to give any third party, for a charge no more than your
144 cost of physically performing source distribution, a complete
145 machine-readable copy of the corresponding source code, to be
146 distributed under the terms of Sections 1 and 2 above on a medium
147 customarily used for software interchange; or,
148
149 c) Accompany it with the information you received as to the offer
150 to distribute corresponding source code. (This alternative is
151 allowed only for noncommercial distribution and only if you
152 received the program in object code or executable form with such
153 an offer, in accord with Subsection b above.)
154
155The source code for a work means the preferred form of the work for
156making modifications to it. For an executable work, complete source
157code means all the source code for all modules it contains, plus any
158associated interface definition files, plus the scripts used to
159control compilation and installation of the executable. However, as a
160special exception, the source code distributed need not include
161anything that is normally distributed (in either source or binary
162form) with the major components (compiler, kernel, and so on) of the
163operating system on which the executable runs, unless that component
164itself accompanies the executable.
165
166If distribution of executable or object code is made by offering
167access to copy from a designated place, then offering equivalent
168access to copy the source code from the same place counts as
169distribution of the source code, even though third parties are not
170compelled to copy the source along with the object code.
171
172 4. You may not copy, modify, sublicense, or distribute the Program
173except as expressly provided under this License. Any attempt
174otherwise to copy, modify, sublicense or distribute the Program is
175void, and will automatically terminate your rights under this License.
176However, parties who have received copies, or rights, from you under
177this License will not have their licenses terminated so long as such
178parties remain in full compliance.
179
180 5. You are not required to accept this License, since you have not
181signed it. However, nothing else grants you permission to modify or
182distribute the Program or its derivative works. These actions are
183prohibited by law if you do not accept this License. Therefore, by
184modifying or distributing the Program (or any work based on the
185Program), you indicate your acceptance of this License to do so, and
186all its terms and conditions for copying, distributing or modifying
187the Program or works based on it.
188
189 6. Each time you redistribute the Program (or any work based on the
190Program), the recipient automatically receives a license from the
191original licensor to copy, distribute or modify the Program subject to
192these terms and conditions. You may not impose any further
193restrictions on the recipients' exercise of the rights granted herein.
194You are not responsible for enforcing compliance by third parties to
195this License.
196
197 7. If, as a consequence of a court judgment or allegation of patent
198infringement or for any other reason (not limited to patent issues),
199conditions are imposed on you (whether by court order, agreement or
200otherwise) that contradict the conditions of this License, they do not
201excuse you from the conditions of this License. If you cannot
202distribute so as to satisfy simultaneously your obligations under this
203License and any other pertinent obligations, then as a consequence you
204may not distribute the Program at all. For example, if a patent
205license would not permit royalty-free redistribution of the Program by
206all those who receive copies directly or indirectly through you, then
207the only way you could satisfy both it and this License would be to
208refrain entirely from distribution of the Program.
209
210If any portion of this section is held invalid or unenforceable under
211any particular circumstance, the balance of the section is intended to
212apply and the section as a whole is intended to apply in other
213circumstances.
214
215It is not the purpose of this section to induce you to infringe any
216patents or other property right claims or to contest validity of any
217such claims; this section has the sole purpose of protecting the
218integrity of the free software distribution system, which is
219implemented by public license practices. Many people have made
220generous contributions to the wide range of software distributed
221through that system in reliance on consistent application of that
222system; it is up to the author/donor to decide if he or she is willing
223to distribute software through any other system and a licensee cannot
224impose that choice.
225
226This section is intended to make thoroughly clear what is believed to
227be a consequence of the rest of this License.
228
229 8. If the distribution and/or use of the Program is restricted in
230certain countries either by patents or by copyrighted interfaces, the
231original copyright holder who places the Program under this License
232may add an explicit geographical distribution limitation excluding
233those countries, so that distribution is permitted only in or among
234countries not thus excluded. In such case, this License incorporates
235the limitation as if written in the body of this License.
236
237 9. The Free Software Foundation may publish revised and/or new versions
238of the General Public License from time to time. Such new versions will
239be similar in spirit to the present version, but may differ in detail to
240address new problems or concerns.
241
242Each version is given a distinguishing version number. If the Program
243specifies a version number of this License which applies to it and "any
244later version", you have the option of following the terms and conditions
245either of that version or of any later version published by the Free
246Software Foundation. If the Program does not specify a version number of
247this License, you may choose any version ever published by the Free Software
248Foundation.
249
250 10. If you wish to incorporate parts of the Program into other free
251programs whose distribution conditions are different, write to the author
252to ask for permission. For software which is copyrighted by the Free
253Software Foundation, write to the Free Software Foundation; we sometimes
254make exceptions for this. Our decision will be guided by the two goals
255of preserving the free status of all derivatives of our free software and
256of promoting the sharing and reuse of software generally.
257
258 NO WARRANTY
259
260 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268REPAIR OR CORRECTION.
269
270 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278POSSIBILITY OF SUCH DAMAGES.
279
280 END OF TERMS AND CONDITIONS
281
282 How to Apply These Terms to Your New Programs
283
284 If you develop a new program, and you want it to be of the greatest
285possible use to the public, the best way to achieve this is to make it
286free software which everyone can redistribute and change under these terms.
287
288 To do so, attach the following notices to the program. It is safest
289to attach them to the start of each source file to most effectively
290convey the exclusion of warranty; and each file should have at least
291the "copyright" line and a pointer to where the full notice is found.
292
293 <one line to give the program's name and a brief idea of what it does.>
294 Copyright (C) <year> <name of author>
295
296 This program is free software; you can redistribute it and/or modify
297 it under the terms of the GNU General Public License as published by
298 the Free Software Foundation; either version 2 of the License, or
299 (at your option) any later version.
300
301 This program is distributed in the hope that it will be useful,
302 but WITHOUT ANY WARRANTY; without even the implied warranty of
303 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 GNU General Public License for more details.
305
306 You should have received a copy of the GNU General Public License along
307 with this program; if not, write to the Free Software Foundation, Inc.,
308 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309
310Also add information on how to contact you by electronic and paper mail.
311
312If the program is interactive, make it output a short notice like this
313when it starts in an interactive mode:
314
315 Gnomovision version 69, Copyright (C) year name of author
316 Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 This is free software, and you are welcome to redistribute it
318 under certain conditions; type `show c' for details.
319
320The hypothetical commands `show w' and `show c' should show the appropriate
321parts of the General Public License. Of course, the commands you use may
322be called something other than `show w' and `show c'; they could even be
323mouse-clicks or menu items--whatever suits your program.
324
325You should also get your employer (if you work as a programmer) or your
326school, if any, to sign a "copyright disclaimer" for the program, if
327necessary. Here is a sample; alter the names:
328
329 Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 `Gnomovision' (which makes passes at compilers) written by James Hacker.
331
332 <signature of Ty Coon>, 1 April 1989
333 Ty Coon, President of Vice
334
335This General Public License does not permit incorporating your program into
336proprietary programs. If your program is a subroutine library, you may
337consider it more useful to permit linking proprietary applications with the
338library. If this is what you want to do, use the GNU Lesser General
339Public License instead of this License.
diff --git a/drivers/gator/Makefile b/drivers/gator/Makefile
new file mode 100644
index 00000000000..2f86823313c
--- /dev/null
+++ b/drivers/gator/Makefile
@@ -0,0 +1,81 @@
1ifneq ($(KERNELRELEASE),)
2
3# Uncomment the following line to enable kernel stack unwinding within gator, or update gator_backtrace.c
4# EXTRA_CFLAGS += -DGATOR_KERNEL_STACK_UNWINDING
5
6CONFIG_GATOR ?= m
7obj-$(CONFIG_GATOR) := gator.o
8
9gator-y := gator_main.o \
10 gator_events_block.o \
11 gator_events_irq.o \
12 gator_events_meminfo.o \
13 gator_events_mmapped.o \
14 gator_events_net.o \
15 gator_events_perf_pmu.o \
16 gator_events_sched.o \
17 gator_events_threads.o \
18
19# Convert the old GATOR_WITH_MALI_SUPPORT to the new kernel flags
20ifneq ($(GATOR_WITH_MALI_SUPPORT),)
21 CONFIG_GATOR_WITH_MALI_SUPPORT := y
22 ifeq ($(GATOR_WITH_MALI_SUPPORT),MALI_T6xx)
23 CONFIG_GATOR_MALI_4XXMP := n
24 CONFIG_GATOR_MALI_T6XX := y
25 else
26 CONFIG_GATOR_MALI_4XXMP := y
27 CONFIG_GATOR_MALI_T6XX := n
28 endif
29 EXTRA_CFLAGS += -DMALI_SUPPORT=$(GATOR_WITH_MALI_SUPPORT)
30 ifneq ($(GATOR_MALI_INTERFACE_STYLE),)
31 EXTRA_CFLAGS += -DGATOR_MALI_INTERFACE_STYLE=$(GATOR_MALI_INTERFACE_STYLE)
32 endif
33endif
34
35ifeq ($(CONFIG_GATOR_WITH_MALI_SUPPORT),y)
36 ifeq ($(CONFIG_GATOR_MALI_T6XX),y)
37 gator-y += gator_events_mali_t6xx.o \
38 gator_events_mali_t6xx_hw.o
39 include $(src)/mali_t6xx.mk
40 else
41 gator-y += gator_events_mali_4xx.o
42 endif
43 gator-y += gator_events_mali_common.o
44
45 ifneq ($(CONFIG_GATOR_MALI_PATH),)
46 ccflags-y += -I$(CONFIG_GATOR_MALI_PATH)
47 endif
48 ccflags-$(CONFIG_GATOR_MALI_4XXMP) += -DMALI_SUPPORT=MALI_4xx
49 ccflags-$(CONFIG_GATOR_MALI_T6XX) += -DMALI_SUPPORT=MALI_T6xx
50endif
51
52# GATOR_TEST controls whether to include (=1) or exclude (=0) test code.
53GATOR_TEST ?= 0
54EXTRA_CFLAGS += -DGATOR_TEST=$(GATOR_TEST)
55
56# Should the original or new block_rq_complete API be used?
57OLD_BLOCK_RQ_COMPLETE := $(shell grep -A3 block_rq_complete include/trace/events/block.h | grep nr_bytes > /dev/null; echo $$?)
58EXTRA_CFLAGS += -DOLD_BLOCK_RQ_COMPLETE=$(OLD_BLOCK_RQ_COMPLETE)
59
60gator-$(CONFIG_ARM) += gator_events_armv6.o \
61 gator_events_armv7.o \
62 gator_events_ccn-504.o \
63 gator_events_l2c-310.o \
64 gator_events_scorpion.o
65
66gator-$(CONFIG_ARM64) += gator_events_ccn-504.o
67
68else
69
70all:
71 @echo
72 @echo "usage:"
73 @echo " make -C <kernel_build_dir> M=\`pwd\` ARCH=arm CROSS_COMPILE=<...> modules"
74 @echo
75 $(error)
76
77clean:
78 rm -f *.o .*.cmd modules.order Module.symvers gator.ko gator.mod.c
79 rm -rf .tmp_versions
80
81endif
diff --git a/drivers/gator/gator.h b/drivers/gator/gator.h
new file mode 100644
index 00000000000..5ad0254d86a
--- /dev/null
+++ b/drivers/gator/gator.h
@@ -0,0 +1,149 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef GATOR_H_
10#define GATOR_H_
11
12#include <linux/version.h>
13#include <linux/fs.h>
14#include <linux/mm.h>
15#include <linux/list.h>
16
17#define GATOR_PERF_SUPPORT LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
18#define GATOR_PERF_PMU_SUPPORT GATOR_PERF_SUPPORT && defined(CONFIG_PERF_EVENTS) && (!(defined(__arm__) || defined(__aarch64__)) || defined(CONFIG_HW_PERF_EVENTS))
19#define GATOR_NO_PERF_SUPPORT (!(GATOR_PERF_SUPPORT))
20#define GATOR_CPU_FREQ_SUPPORT (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)) && defined(CONFIG_CPU_FREQ)
21#define GATOR_IKS_SUPPORT defined(CONFIG_BL_SWITCHER)
22
23// cpu ids
24#define ARM1136 0xb36
25#define ARM1156 0xb56
26#define ARM1176 0xb76
27#define ARM11MPCORE 0xb02
28#define CORTEX_A5 0xc05
29#define CORTEX_A7 0xc07
30#define CORTEX_A8 0xc08
31#define CORTEX_A9 0xc09
32#define CORTEX_A12 0xc0d
33#define CORTEX_A15 0xc0f
34#define CORTEX_A17 0xc0e
35#define SCORPION 0x00f
36#define SCORPIONMP 0x02d
37#define KRAITSIM 0x049
38#define KRAIT 0x04d
39#define KRAIT_S4_PRO 0x06f
40#define CORTEX_A53 0xd03
41#define CORTEX_A57 0xd07
42#define AARCH64 0xd0f
43#define OTHER 0xfff
44
45// gpu enums
46#define MALI_4xx 1
47#define MALI_T6xx 2
48
49#define MAXSIZE_CORE_NAME 32
50
51struct gator_cpu {
52 const int cpuid;
53 // Human readable name
54 const char core_name[MAXSIZE_CORE_NAME];
55 // gatorfs event and Perf PMU name
56 const char * const pmnc_name;
57 // compatible from Documentation/devicetree/bindings/arm/cpus.txt
58 const char * const dt_name;
59 const int pmnc_counters;
60};
61
62const struct gator_cpu *gator_find_cpu_by_cpuid(const u32 cpuid);
63const struct gator_cpu *gator_find_cpu_by_pmu_name(const char *const name);
64
65/******************************************************************************
66 * Filesystem
67 ******************************************************************************/
68struct dentry *gatorfs_mkdir(struct super_block *sb, struct dentry *root,
69 char const *name);
70
71int gatorfs_create_ulong(struct super_block *sb, struct dentry *root,
72 char const *name, unsigned long *val);
73
74int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root,
75 char const *name, unsigned long *val);
76
77/******************************************************************************
78 * Tracepoints
79 ******************************************************************************/
80#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
81# error Kernels prior to 2.6.32 not supported
82#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
83# define GATOR_DEFINE_PROBE(probe_name, proto) \
84 static void probe_##probe_name(PARAMS(proto))
85# define GATOR_REGISTER_TRACE(probe_name) \
86 register_trace_##probe_name(probe_##probe_name)
87# define GATOR_UNREGISTER_TRACE(probe_name) \
88 unregister_trace_##probe_name(probe_##probe_name)
89#elif LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0)
90# define GATOR_DEFINE_PROBE(probe_name, proto) \
91 static void probe_##probe_name(void *data, PARAMS(proto))
92# define GATOR_REGISTER_TRACE(probe_name) \
93 register_trace_##probe_name(probe_##probe_name, NULL)
94# define GATOR_UNREGISTER_TRACE(probe_name) \
95 unregister_trace_##probe_name(probe_##probe_name, NULL)
96#else
97# define GATOR_DEFINE_PROBE(probe_name, proto) \
98 extern struct tracepoint *gator_tracepoint_##probe_name; \
99 static void probe_##probe_name(void *data, PARAMS(proto))
100# define GATOR_REGISTER_TRACE(probe_name) \
101 tracepoint_probe_register(gator_tracepoint_##probe_name, probe_##probe_name, NULL)
102# define GATOR_UNREGISTER_TRACE(probe_name) \
103 tracepoint_probe_unregister(gator_tracepoint_##probe_name, probe_##probe_name, NULL)
104#endif
105
106/******************************************************************************
107 * Events
108 ******************************************************************************/
109struct gator_interface {
110 void (*shutdown)(void); // Complementary function to init
111 int (*create_files)(struct super_block *sb, struct dentry *root);
112 int (*start)(void);
113 void (*stop)(void); // Complementary function to start
114 int (*online)(int **buffer, bool migrate);
115 int (*offline)(int **buffer, bool migrate);
116 void (*online_dispatch)(int cpu, bool migrate); // called in process context but may not be running on core 'cpu'
117 void (*offline_dispatch)(int cpu, bool migrate); // called in process context but may not be running on core 'cpu'
118 int (*read)(int **buffer);
119 int (*read64)(long long **buffer);
120 int (*read_proc)(long long **buffer, struct task_struct *);
121 struct list_head list;
122};
123
124int gator_events_install(struct gator_interface *interface);
125int gator_events_get_key(void);
126u32 gator_cpuid(void);
127
128void gator_backtrace_handler(struct pt_regs *const regs);
129
130void gator_marshal_activity_switch(int core, int key, int activity, int pid);
131
132#if !GATOR_IKS_SUPPORT
133
134#define get_physical_cpu() smp_processor_id()
135#define lcpu_to_pcpu(lcpu) lcpu
136#define pcpu_to_lcpu(pcpu) pcpu
137
138#else
139
140#define get_physical_cpu() lcpu_to_pcpu(get_logical_cpu())
141int lcpu_to_pcpu(const int lcpu);
142int pcpu_to_lcpu(const int pcpu);
143
144#endif
145
146#define get_logical_cpu() smp_processor_id()
147#define on_primary_core() (get_logical_cpu() == 0)
148
149#endif // GATOR_H_
diff --git a/drivers/gator/gator_annotate.c b/drivers/gator/gator_annotate.c
new file mode 100644
index 00000000000..7e2c6e5d871
--- /dev/null
+++ b/drivers/gator/gator_annotate.c
@@ -0,0 +1,186 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10#include <linux/slab.h>
11#include <linux/fs.h>
12#include <linux/mm.h>
13#include <linux/sched.h>
14#include <asm/uaccess.h>
15#include <asm/current.h>
16#include <linux/spinlock.h>
17
18static DEFINE_SPINLOCK(annotate_lock);
19static bool collect_annotations = false;
20
21static int annotate_copy(struct file *file, char const __user *buf, size_t count)
22{
23 int cpu = 0;
24 int write = per_cpu(gator_buffer_write, cpu)[ANNOTATE_BUF];
25
26 if (file == NULL) {
27 // copy from kernel
28 memcpy(&per_cpu(gator_buffer, cpu)[ANNOTATE_BUF][write], buf, count);
29 } else {
30 // copy from user space
31 if (copy_from_user(&per_cpu(gator_buffer, cpu)[ANNOTATE_BUF][write], buf, count) != 0)
32 return -1;
33 }
34 per_cpu(gator_buffer_write, cpu)[ANNOTATE_BUF] = (write + count) & gator_buffer_mask[ANNOTATE_BUF];
35
36 return 0;
37}
38
39static ssize_t annotate_write(struct file *file, char const __user *buf, size_t count_orig, loff_t *offset)
40{
41 int pid, cpu, header_size, available, contiguous, length1, length2, size, count = count_orig & 0x7fffffff;
42 bool interrupt_context;
43
44 if (*offset) {
45 return -EINVAL;
46 }
47
48 interrupt_context = in_interrupt();
49 // Annotations are not supported in interrupt context, but may work if you comment out the the next four lines of code.
50 // By doing so, annotations in interrupt context can result in deadlocks and lost data.
51 if (interrupt_context) {
52 printk(KERN_WARNING "gator: Annotations are not supported in interrupt context. Edit gator_annotate.c in the gator driver to enable annotations in interrupt context.\n");
53 return -EINVAL;
54 }
55
56 retry:
57 // synchronize between cores and with collect_annotations
58 spin_lock(&annotate_lock);
59
60 if (!collect_annotations) {
61 // Not collecting annotations, tell the caller everything was written
62 size = count_orig;
63 goto annotate_write_out;
64 }
65
66 // Annotation only uses a single per-cpu buffer as the data must be in order to the engine
67 cpu = 0;
68
69 if (current == NULL) {
70 pid = 0;
71 } else {
72 pid = current->pid;
73 }
74
75 // determine total size of the payload
76 header_size = MAXSIZE_PACK32 * 3 + MAXSIZE_PACK64;
77 available = buffer_bytes_available(cpu, ANNOTATE_BUF) - header_size;
78 size = count < available ? count : available;
79
80 if (size <= 0) {
81 // Buffer is full, wait until space is available
82 spin_unlock(&annotate_lock);
83
84 // Drop the annotation as blocking is not allowed in interrupt context
85 if (interrupt_context) {
86 return -EINVAL;
87 }
88
89 wait_event_interruptible(gator_annotate_wait, buffer_bytes_available(cpu, ANNOTATE_BUF) > header_size || !collect_annotations);
90
91 // Check to see if a signal is pending
92 if (signal_pending(current)) {
93 return -EINTR;
94 }
95
96 goto retry;
97 }
98
99 // synchronize shared variables annotateBuf and annotatePos
100 if (per_cpu(gator_buffer, cpu)[ANNOTATE_BUF]) {
101 u64 time = gator_get_time();
102 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, get_physical_cpu());
103 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, pid);
104 gator_buffer_write_packed_int64(cpu, ANNOTATE_BUF, time);
105 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, size);
106
107 // determine the sizes to capture, length1 + length2 will equal size
108 contiguous = contiguous_space_available(cpu, ANNOTATE_BUF);
109 if (size < contiguous) {
110 length1 = size;
111 length2 = 0;
112 } else {
113 length1 = contiguous;
114 length2 = size - contiguous;
115 }
116
117 if (annotate_copy(file, buf, length1) != 0) {
118 size = -EINVAL;
119 goto annotate_write_out;
120 }
121
122 if (length2 > 0 && annotate_copy(file, &buf[length1], length2) != 0) {
123 size = -EINVAL;
124 goto annotate_write_out;
125 }
126
127 // Check and commit; commit is set to occur once buffer is 3/4 full
128 buffer_check(cpu, ANNOTATE_BUF, time);
129 }
130
131annotate_write_out:
132 spin_unlock(&annotate_lock);
133
134 // return the number of bytes written
135 return size;
136}
137
138#include "gator_annotate_kernel.c"
139
140static int annotate_release(struct inode *inode, struct file *file)
141{
142 int cpu = 0;
143
144 // synchronize between cores
145 spin_lock(&annotate_lock);
146
147 if (per_cpu(gator_buffer, cpu)[ANNOTATE_BUF] && buffer_check_space(cpu, ANNOTATE_BUF, MAXSIZE_PACK64 + 3 * MAXSIZE_PACK32)) {
148 uint32_t pid = current->pid;
149 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, get_physical_cpu());
150 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, pid);
151 gator_buffer_write_packed_int64(cpu, ANNOTATE_BUF, 0); // time
152 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, 0); // size
153 }
154
155 // Check and commit; commit is set to occur once buffer is 3/4 full
156 buffer_check(cpu, ANNOTATE_BUF, gator_get_time());
157
158 spin_unlock(&annotate_lock);
159
160 return 0;
161}
162
163static const struct file_operations annotate_fops = {
164 .write = annotate_write,
165 .release = annotate_release
166};
167
168static int gator_annotate_create_files(struct super_block *sb, struct dentry *root)
169{
170 return gatorfs_create_file_perm(sb, root, "annotate", &annotate_fops, 0666);
171}
172
173static int gator_annotate_start(void)
174{
175 collect_annotations = true;
176 return 0;
177}
178
179static void gator_annotate_stop(void)
180{
181 // the spinlock here will ensure that when this function exits, we are not in the middle of an annotation
182 spin_lock(&annotate_lock);
183 collect_annotations = false;
184 wake_up(&gator_annotate_wait);
185 spin_unlock(&annotate_lock);
186}
diff --git a/drivers/gator/gator_annotate_kernel.c b/drivers/gator/gator_annotate_kernel.c
new file mode 100644
index 00000000000..01080682552
--- /dev/null
+++ b/drivers/gator/gator_annotate_kernel.c
@@ -0,0 +1,202 @@
1/**
2 * Copyright (C) ARM Limited 2012-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10#define ESCAPE_CODE 0x1c
11#define STRING_ANNOTATION 0x06
12#define NAME_CHANNEL_ANNOTATION 0x07
13#define NAME_GROUP_ANNOTATION 0x08
14#define VISUAL_ANNOTATION 0x04
15#define MARKER_ANNOTATION 0x05
16
17static void kannotate_write(const char *ptr, unsigned int size)
18{
19 int retval;
20 int pos = 0;
21 loff_t offset = 0;
22 while (pos < size) {
23 retval = annotate_write(NULL, &ptr[pos], size - pos, &offset);
24 if (retval < 0) {
25 printk(KERN_WARNING "gator: kannotate_write failed with return value %d\n", retval);
26 return;
27 }
28 pos += retval;
29 }
30}
31
32static void marshal_u16(char *buf, u16 val)
33{
34 buf[0] = val & 0xff;
35 buf[1] = (val >> 8) & 0xff;
36}
37
38static void marshal_u32(char *buf, u32 val)
39{
40 buf[0] = val & 0xff;
41 buf[1] = (val >> 8) & 0xff;
42 buf[2] = (val >> 16) & 0xff;
43 buf[3] = (val >> 24) & 0xff;
44}
45
46void gator_annotate_channel(int channel, const char *str)
47{
48 const u16 str_size = strlen(str) & 0xffff;
49 char header[8];
50 header[0] = ESCAPE_CODE;
51 header[1] = STRING_ANNOTATION;
52 marshal_u32(header + 2, channel);
53 marshal_u16(header + 6, str_size);
54 kannotate_write(header, sizeof(header));
55 kannotate_write(str, str_size);
56}
57
58EXPORT_SYMBOL(gator_annotate_channel);
59
60void gator_annotate(const char *str)
61{
62 gator_annotate_channel(0, str);
63}
64
65EXPORT_SYMBOL(gator_annotate);
66
67void gator_annotate_channel_color(int channel, int color, const char *str)
68{
69 const u16 str_size = (strlen(str) + 4) & 0xffff;
70 char header[12];
71 header[0] = ESCAPE_CODE;
72 header[1] = STRING_ANNOTATION;
73 marshal_u32(header + 2, channel);
74 marshal_u16(header + 6, str_size);
75 marshal_u32(header + 8, color);
76 kannotate_write(header, sizeof(header));
77 kannotate_write(str, str_size - 4);
78}
79
80EXPORT_SYMBOL(gator_annotate_channel_color);
81
82void gator_annotate_color(int color, const char *str)
83{
84 gator_annotate_channel_color(0, color, str);
85}
86
87EXPORT_SYMBOL(gator_annotate_color);
88
89void gator_annotate_channel_end(int channel)
90{
91 char header[8];
92 header[0] = ESCAPE_CODE;
93 header[1] = STRING_ANNOTATION;
94 marshal_u32(header + 2, channel);
95 marshal_u16(header + 6, 0);
96 kannotate_write(header, sizeof(header));
97}
98
99EXPORT_SYMBOL(gator_annotate_channel_end);
100
101void gator_annotate_end(void)
102{
103 gator_annotate_channel_end(0);
104}
105
106EXPORT_SYMBOL(gator_annotate_end);
107
108void gator_annotate_name_channel(int channel, int group, const char* str)
109{
110 const u16 str_size = strlen(str) & 0xffff;
111 char header[12];
112 header[0] = ESCAPE_CODE;
113 header[1] = NAME_CHANNEL_ANNOTATION;
114 marshal_u32(header + 2, channel);
115 marshal_u32(header + 6, group);
116 marshal_u16(header + 10, str_size);
117 kannotate_write(header, sizeof(header));
118 kannotate_write(str, str_size);
119}
120
121EXPORT_SYMBOL(gator_annotate_name_channel);
122
123void gator_annotate_name_group(int group, const char* str)
124{
125 const u16 str_size = strlen(str) & 0xffff;
126 char header[8];
127 header[0] = ESCAPE_CODE;
128 header[1] = NAME_GROUP_ANNOTATION;
129 marshal_u32(header + 2, group);
130 marshal_u16(header + 6, str_size);
131 kannotate_write(header, sizeof(header));
132 kannotate_write(str, str_size);
133}
134
135EXPORT_SYMBOL(gator_annotate_name_group);
136
137void gator_annotate_visual(const char *data, unsigned int length, const char *str)
138{
139 const u16 str_size = strlen(str) & 0xffff;
140 char header[4];
141 char header_length[4];
142 header[0] = ESCAPE_CODE;
143 header[1] = VISUAL_ANNOTATION;
144 marshal_u16(header + 2, str_size);
145 marshal_u32(header_length, length);
146 kannotate_write(header, sizeof(header));
147 kannotate_write(str, str_size);
148 kannotate_write(header_length, sizeof(header_length));
149 kannotate_write(data, length);
150}
151
152EXPORT_SYMBOL(gator_annotate_visual);
153
154void gator_annotate_marker(void)
155{
156 char header[4];
157 header[0] = ESCAPE_CODE;
158 header[1] = MARKER_ANNOTATION;
159 marshal_u16(header + 2, 0);
160 kannotate_write(header, sizeof(header));
161}
162
163EXPORT_SYMBOL(gator_annotate_marker);
164
165void gator_annotate_marker_str(const char *str)
166{
167 const u16 str_size = strlen(str) & 0xffff;
168 char header[4];
169 header[0] = ESCAPE_CODE;
170 header[1] = MARKER_ANNOTATION;
171 marshal_u16(header + 2, str_size);
172 kannotate_write(header, sizeof(header));
173 kannotate_write(str, str_size);
174}
175
176EXPORT_SYMBOL(gator_annotate_marker_str);
177
178void gator_annotate_marker_color(int color)
179{
180 char header[8];
181 header[0] = ESCAPE_CODE;
182 header[1] = MARKER_ANNOTATION;
183 marshal_u16(header + 2, 4);
184 marshal_u32(header + 4, color);
185 kannotate_write(header, sizeof(header));
186}
187
188EXPORT_SYMBOL(gator_annotate_marker_color);
189
190void gator_annotate_marker_color_str(int color, const char *str)
191{
192 const u16 str_size = (strlen(str) + 4) & 0xffff;
193 char header[8];
194 header[0] = ESCAPE_CODE;
195 header[1] = MARKER_ANNOTATION;
196 marshal_u16(header + 2, str_size);
197 marshal_u32(header + 4, color);
198 kannotate_write(header, sizeof(header));
199 kannotate_write(str, str_size - 4);
200}
201
202EXPORT_SYMBOL(gator_annotate_marker_color_str);
diff --git a/drivers/gator/gator_backtrace.c b/drivers/gator/gator_backtrace.c
new file mode 100644
index 00000000000..e03c1653c5b
--- /dev/null
+++ b/drivers/gator/gator_backtrace.c
@@ -0,0 +1,208 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10/*
11 * EABI backtrace stores {fp,lr} on the stack.
12 */
13struct stack_frame_eabi {
14 union {
15 struct {
16 unsigned long fp;
17 // May be the fp in the case of a leaf function or clang
18 unsigned long lr;
19 // If lr is really the fp, lr2 is the corresponding lr
20 unsigned long lr2;
21 };
22 // Used to read 32 bit fp/lr from a 64 bit kernel
23 struct {
24 u32 fp_32;
25 // same as lr above
26 u32 lr_32;
27 // same as lr2 above
28 u32 lr2_32;
29 };
30 };
31};
32
33static void gator_add_trace(int cpu, unsigned long address)
34{
35 off_t offset = 0;
36 unsigned long cookie = get_address_cookie(cpu, current, address & ~1, &offset);
37
38 if (cookie == NO_COOKIE || cookie == UNRESOLVED_COOKIE) {
39 offset = address;
40 }
41
42 marshal_backtrace(offset & ~1, cookie, 0);
43}
44
45static void arm_backtrace_eabi(int cpu, struct pt_regs *const regs, unsigned int depth)
46{
47#if defined(__arm__) || defined(__aarch64__)
48 struct stack_frame_eabi *curr;
49 struct stack_frame_eabi bufcurr;
50#if defined(__arm__)
51 const bool is_compat = false;
52 unsigned long fp = regs->ARM_fp;
53 unsigned long sp = regs->ARM_sp;
54 unsigned long lr = regs->ARM_lr;
55 const int gcc_frame_offset = sizeof(unsigned long);
56#else
57 // Is userspace aarch32 (32 bit)
58 const bool is_compat = compat_user_mode(regs);
59 unsigned long fp = (is_compat ? regs->regs[11] : regs->regs[29]);
60 unsigned long sp = (is_compat ? regs->compat_sp : regs->sp);
61 unsigned long lr = (is_compat ? regs->compat_lr : regs->regs[30]);
62 const int gcc_frame_offset = (is_compat ? sizeof(u32) : 0);
63#endif
64 // clang frame offset is always zero
65 int is_user_mode = user_mode(regs);
66
67 // pc (current function) has already been added
68
69 if (!is_user_mode) {
70 return;
71 }
72
73 // Add the lr (parent function)
74 // entry preamble may not have executed
75 gator_add_trace(cpu, lr);
76
77 // check fp is valid
78 if (fp == 0 || fp < sp) {
79 return;
80 }
81
82 // Get the current stack frame
83 curr = (struct stack_frame_eabi *)(fp - gcc_frame_offset);
84 if ((unsigned long)curr & 3) {
85 return;
86 }
87
88 while (depth-- && curr) {
89 if (!access_ok(VERIFY_READ, curr, sizeof(struct stack_frame_eabi)) ||
90 __copy_from_user_inatomic(&bufcurr, curr, sizeof(struct stack_frame_eabi))) {
91 return;
92 }
93
94 fp = (is_compat ? bufcurr.fp_32 : bufcurr.fp);
95 lr = (is_compat ? bufcurr.lr_32 : bufcurr.lr);
96
97#define calc_next(reg) ((reg) - gcc_frame_offset)
98 // Returns true if reg is a valid fp
99#define validate_next(reg, curr) \
100 ((reg) != 0 && (calc_next(reg) & 3) == 0 && (unsigned long)(curr) < calc_next(reg))
101
102 // Try lr from the stack as the fp because gcc leaf functions do not push lr
103 // If gcc_frame_offset is non-zero, the lr will also be the clang fp
104 // This assumes code is at a lower address than the stack
105 if (validate_next(lr, curr)) {
106 fp = lr;
107 lr = (is_compat ? bufcurr.lr2_32 : bufcurr.lr2);
108 }
109
110 gator_add_trace(cpu, lr);
111
112 if (!validate_next(fp, curr)) {
113 return;
114 }
115
116 // Move to the next stack frame
117 curr = (struct stack_frame_eabi *)calc_next(fp);
118 }
119#endif
120}
121
122#if defined(__arm__) || defined(__aarch64__)
123static int report_trace(struct stackframe *frame, void *d)
124{
125 unsigned int *depth = d, cookie = NO_COOKIE;
126 unsigned long addr = frame->pc;
127
128 if (*depth) {
129#if defined(MODULE)
130 unsigned int cpu = get_physical_cpu();
131 struct module *mod = __module_address(addr);
132 if (mod) {
133 cookie = get_cookie(cpu, current, mod->name, false);
134 addr = addr - (unsigned long)mod->module_core;
135 }
136#endif
137 marshal_backtrace(addr & ~1, cookie, 1);
138 (*depth)--;
139 }
140
141 return *depth == 0;
142}
143#endif
144
145// Uncomment the following line to enable kernel stack unwinding within gator, note it can also be defined from the Makefile
146// #define GATOR_KERNEL_STACK_UNWINDING
147
148#if (defined(__arm__) || defined(__aarch64__)) && !defined(GATOR_KERNEL_STACK_UNWINDING)
149// Disabled by default
150MODULE_PARM_DESC(kernel_stack_unwinding, "Allow kernel stack unwinding.");
151static bool kernel_stack_unwinding = 0;
152module_param(kernel_stack_unwinding, bool, 0644);
153#endif
154
155static void kernel_backtrace(int cpu, struct pt_regs *const regs)
156{
157#if defined(__arm__) || defined(__aarch64__)
158#ifdef GATOR_KERNEL_STACK_UNWINDING
159 int depth = gator_backtrace_depth;
160#else
161 int depth = (kernel_stack_unwinding ? gator_backtrace_depth : 1);
162#endif
163 struct stackframe frame;
164 if (depth == 0)
165 depth = 1;
166#if defined(__arm__)
167 frame.fp = regs->ARM_fp;
168 frame.sp = regs->ARM_sp;
169 frame.lr = regs->ARM_lr;
170 frame.pc = regs->ARM_pc;
171#else
172 frame.fp = regs->regs[29];
173 frame.sp = regs->sp;
174 frame.pc = regs->pc;
175#endif
176 walk_stackframe(&frame, report_trace, &depth);
177#else
178 marshal_backtrace(PC_REG & ~1, NO_COOKIE, 1);
179#endif
180}
181
182static void gator_add_sample(int cpu, struct pt_regs *const regs, u64 time)
183{
184 bool in_kernel;
185 unsigned long exec_cookie;
186
187 if (!regs)
188 return;
189
190 in_kernel = !user_mode(regs);
191 exec_cookie = get_exec_cookie(cpu, current);
192
193 if (!marshal_backtrace_header(exec_cookie, current->tgid, current->pid, time))
194 return;
195
196 if (in_kernel) {
197 kernel_backtrace(cpu, regs);
198 } else {
199 // Cookie+PC
200 gator_add_trace(cpu, PC_REG);
201
202 // Backtrace
203 if (gator_backtrace_depth)
204 arm_backtrace_eabi(cpu, regs, gator_backtrace_depth);
205 }
206
207 marshal_backtrace_footer(time);
208}
diff --git a/drivers/gator/gator_buffer.c b/drivers/gator/gator_buffer.c
new file mode 100644
index 00000000000..dfbc97d8022
--- /dev/null
+++ b/drivers/gator/gator_buffer.c
@@ -0,0 +1,168 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10static void marshal_frame(int cpu, int buftype)
11{
12 int frame;
13
14 if (!per_cpu(gator_buffer, cpu)[buftype]) {
15 return;
16 }
17
18 switch (buftype) {
19 case SUMMARY_BUF:
20 frame = FRAME_SUMMARY;
21 break;
22 case BACKTRACE_BUF:
23 frame = FRAME_BACKTRACE;
24 break;
25 case NAME_BUF:
26 frame = FRAME_NAME;
27 break;
28 case COUNTER_BUF:
29 frame = FRAME_COUNTER;
30 break;
31 case BLOCK_COUNTER_BUF:
32 frame = FRAME_BLOCK_COUNTER;
33 break;
34 case ANNOTATE_BUF:
35 frame = FRAME_ANNOTATE;
36 break;
37 case SCHED_TRACE_BUF:
38 frame = FRAME_SCHED_TRACE;
39 break;
40 case IDLE_BUF:
41 frame = FRAME_IDLE;
42 break;
43 case ACTIVITY_BUF:
44 frame = FRAME_ACTIVITY;
45 break;
46 default:
47 frame = -1;
48 break;
49 }
50
51 // add response type
52 if (gator_response_type > 0) {
53 gator_buffer_write_packed_int(cpu, buftype, gator_response_type);
54 }
55
56 // leave space for 4-byte unpacked length
57 per_cpu(gator_buffer_write, cpu)[buftype] = (per_cpu(gator_buffer_write, cpu)[buftype] + sizeof(s32)) & gator_buffer_mask[buftype];
58
59 // add frame type and core number
60 gator_buffer_write_packed_int(cpu, buftype, frame);
61 gator_buffer_write_packed_int(cpu, buftype, cpu);
62}
63
64static int buffer_bytes_available(int cpu, int buftype)
65{
66 int remaining, filled;
67
68 filled = per_cpu(gator_buffer_write, cpu)[buftype] - per_cpu(gator_buffer_read, cpu)[buftype];
69 if (filled < 0) {
70 filled += gator_buffer_size[buftype];
71 }
72
73 remaining = gator_buffer_size[buftype] - filled;
74
75 if (per_cpu(buffer_space_available, cpu)[buftype]) {
76 // Give some extra room; also allows space to insert the overflow error packet
77 remaining -= 200;
78 } else {
79 // Hysteresis, prevents multiple overflow messages
80 remaining -= 2000;
81 }
82
83 return remaining;
84}
85
86static bool buffer_check_space(int cpu, int buftype, int bytes)
87{
88 int remaining = buffer_bytes_available(cpu, buftype);
89
90 if (remaining < bytes) {
91 per_cpu(buffer_space_available, cpu)[buftype] = false;
92 } else {
93 per_cpu(buffer_space_available, cpu)[buftype] = true;
94 }
95
96 return per_cpu(buffer_space_available, cpu)[buftype];
97}
98
99static int contiguous_space_available(int cpu, int buftype)
100{
101 int remaining = buffer_bytes_available(cpu, buftype);
102 int contiguous = gator_buffer_size[buftype] - per_cpu(gator_buffer_write, cpu)[buftype];
103 if (remaining < contiguous)
104 return remaining;
105 else
106 return contiguous;
107}
108
109static void gator_commit_buffer(int cpu, int buftype, u64 time)
110{
111 int type_length, commit, length, byte;
112 unsigned long flags;
113
114 if (!per_cpu(gator_buffer, cpu)[buftype])
115 return;
116
117 // post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload
118 local_irq_save(flags);
119 type_length = gator_response_type ? 1 : 0;
120 commit = per_cpu(gator_buffer_commit, cpu)[buftype];
121 length = per_cpu(gator_buffer_write, cpu)[buftype] - commit;
122 if (length < 0) {
123 length += gator_buffer_size[buftype];
124 }
125 length = length - type_length - sizeof(s32);
126
127 if (length <= FRAME_HEADER_SIZE) {
128 // Nothing to write, only the frame header is present
129 local_irq_restore(flags);
130 return;
131 }
132
133 for (byte = 0; byte < sizeof(s32); byte++) {
134 per_cpu(gator_buffer, cpu)[buftype][(commit + type_length + byte) & gator_buffer_mask[buftype]] = (length >> byte * 8) & 0xFF;
135 }
136
137 per_cpu(gator_buffer_commit, cpu)[buftype] = per_cpu(gator_buffer_write, cpu)[buftype];
138
139 if (gator_live_rate > 0) {
140 while (time > per_cpu(gator_buffer_commit_time, cpu)) {
141 per_cpu(gator_buffer_commit_time, cpu) += gator_live_rate;
142 }
143 }
144
145 marshal_frame(cpu, buftype);
146 local_irq_restore(flags);
147
148 // had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater
149 if (per_cpu(in_scheduler_context, cpu)) {
150#ifndef CONFIG_PREEMPT_RT_FULL
151 // mod_timer can not be used in interrupt context in RT-Preempt full
152 mod_timer(&gator_buffer_wake_up_timer, jiffies + 1);
153#endif
154 } else {
155 up(&gator_buffer_wake_sem);
156 }
157}
158
159static void buffer_check(int cpu, int buftype, u64 time)
160{
161 int filled = per_cpu(gator_buffer_write, cpu)[buftype] - per_cpu(gator_buffer_commit, cpu)[buftype];
162 if (filled < 0) {
163 filled += gator_buffer_size[buftype];
164 }
165 if (filled >= ((gator_buffer_size[buftype] * 3) / 4)) {
166 gator_commit_buffer(cpu, buftype, time);
167 }
168}
diff --git a/drivers/gator/gator_buffer_write.c b/drivers/gator/gator_buffer_write.c
new file mode 100644
index 00000000000..b621ba93ee5
--- /dev/null
+++ b/drivers/gator/gator_buffer_write.c
@@ -0,0 +1,80 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10static void gator_buffer_write_packed_int(int cpu, int buftype, int x)
11{
12 uint32_t write = per_cpu(gator_buffer_write, cpu)[buftype];
13 uint32_t mask = gator_buffer_mask[buftype];
14 char *buffer = per_cpu(gator_buffer, cpu)[buftype];
15 int packedBytes = 0;
16 int more = true;
17 while (more) {
18 // low order 7 bits of x
19 char b = x & 0x7f;
20 x >>= 7;
21
22 if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) {
23 more = false;
24 } else {
25 b |= 0x80;
26 }
27
28 buffer[(write + packedBytes) & mask] = b;
29 packedBytes++;
30 }
31
32 per_cpu(gator_buffer_write, cpu)[buftype] = (write + packedBytes) & mask;
33}
34
35static void gator_buffer_write_packed_int64(int cpu, int buftype, long long x)
36{
37 uint32_t write = per_cpu(gator_buffer_write, cpu)[buftype];
38 uint32_t mask = gator_buffer_mask[buftype];
39 char *buffer = per_cpu(gator_buffer, cpu)[buftype];
40 int packedBytes = 0;
41 int more = true;
42 while (more) {
43 // low order 7 bits of x
44 char b = x & 0x7f;
45 x >>= 7;
46
47 if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) {
48 more = false;
49 } else {
50 b |= 0x80;
51 }
52
53 buffer[(write + packedBytes) & mask] = b;
54 packedBytes++;
55 }
56
57 per_cpu(gator_buffer_write, cpu)[buftype] = (write + packedBytes) & mask;
58}
59
60static void gator_buffer_write_bytes(int cpu, int buftype, const char *x, int len)
61{
62 int i;
63 u32 write = per_cpu(gator_buffer_write, cpu)[buftype];
64 u32 mask = gator_buffer_mask[buftype];
65 char *buffer = per_cpu(gator_buffer, cpu)[buftype];
66
67 for (i = 0; i < len; i++) {
68 buffer[write] = x[i];
69 write = (write + 1) & mask;
70 }
71
72 per_cpu(gator_buffer_write, cpu)[buftype] = write;
73}
74
75static void gator_buffer_write_string(int cpu, int buftype, const char *x)
76{
77 int len = strlen(x);
78 gator_buffer_write_packed_int(cpu, buftype, len);
79 gator_buffer_write_bytes(cpu, buftype, x, len);
80}
diff --git a/drivers/gator/gator_cookies.c b/drivers/gator/gator_cookies.c
new file mode 100644
index 00000000000..5c7d842070e
--- /dev/null
+++ b/drivers/gator/gator_cookies.c
@@ -0,0 +1,437 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10#define COOKIEMAP_ENTRIES 1024 /* must be power of 2 */
11#define TRANSLATE_BUFFER_SIZE 512 // must be a power of 2 - 512/4 = 128 entries
12#define TRANSLATE_TEXT_SIZE 256
13#define MAX_COLLISIONS 2
14
15static uint32_t *gator_crc32_table;
16static unsigned int translate_buffer_mask;
17
18struct cookie_args {
19 struct task_struct *task;
20 const char *text;
21};
22
23static DEFINE_PER_CPU(char *, translate_text);
24static DEFINE_PER_CPU(uint32_t, cookie_next_key);
25static DEFINE_PER_CPU(uint64_t *, cookie_keys);
26static DEFINE_PER_CPU(uint32_t *, cookie_values);
27static DEFINE_PER_CPU(int, translate_buffer_read);
28static DEFINE_PER_CPU(int, translate_buffer_write);
29static DEFINE_PER_CPU(struct cookie_args *, translate_buffer);
30
31static uint32_t get_cookie(int cpu, struct task_struct *task, const char *text, bool from_wq);
32static void wq_cookie_handler(struct work_struct *unused);
33static DECLARE_WORK(cookie_work, wq_cookie_handler);
34static struct timer_list app_process_wake_up_timer;
35static void app_process_wake_up_handler(unsigned long unused_data);
36
37static uint32_t cookiemap_code(uint64_t value64)
38{
39 uint32_t value = (uint32_t)((value64 >> 32) + value64);
40 uint32_t cookiecode = (value >> 24) & 0xff;
41 cookiecode = cookiecode * 31 + ((value >> 16) & 0xff);
42 cookiecode = cookiecode * 31 + ((value >> 8) & 0xff);
43 cookiecode = cookiecode * 31 + ((value >> 0) & 0xff);
44 cookiecode &= (COOKIEMAP_ENTRIES - 1);
45 return cookiecode * MAX_COLLISIONS;
46}
47
48static uint32_t gator_chksum_crc32(const char *data)
49{
50 register unsigned long crc;
51 const unsigned char *block = data;
52 int i, length = strlen(data);
53
54 crc = 0xFFFFFFFF;
55 for (i = 0; i < length; i++) {
56 crc = ((crc >> 8) & 0x00FFFFFF) ^ gator_crc32_table[(crc ^ *block++) & 0xFF];
57 }
58
59 return (crc ^ 0xFFFFFFFF);
60}
61
62/*
63 * Exists
64 * Pre: [0][1][v][3]..[n-1]
65 * Post: [v][0][1][3]..[n-1]
66 */
67static uint32_t cookiemap_exists(uint64_t key)
68{
69 unsigned long x, flags, retval = 0;
70 int cpu = get_physical_cpu();
71 uint32_t cookiecode = cookiemap_code(key);
72 uint64_t *keys = &(per_cpu(cookie_keys, cpu)[cookiecode]);
73 uint32_t *values = &(per_cpu(cookie_values, cpu)[cookiecode]);
74
75 // Can be called from interrupt handler or from work queue
76 local_irq_save(flags);
77 for (x = 0; x < MAX_COLLISIONS; x++) {
78 if (keys[x] == key) {
79 uint32_t value = values[x];
80 for (; x > 0; x--) {
81 keys[x] = keys[x - 1];
82 values[x] = values[x - 1];
83 }
84 keys[0] = key;
85 values[0] = value;
86 retval = value;
87 break;
88 }
89 }
90 local_irq_restore(flags);
91
92 return retval;
93}
94
95/*
96 * Add
97 * Pre: [0][1][2][3]..[n-1]
98 * Post: [v][0][1][2]..[n-2]
99 */
100static void cookiemap_add(uint64_t key, uint32_t value)
101{
102 int cpu = get_physical_cpu();
103 int cookiecode = cookiemap_code(key);
104 uint64_t *keys = &(per_cpu(cookie_keys, cpu)[cookiecode]);
105 uint32_t *values = &(per_cpu(cookie_values, cpu)[cookiecode]);
106 int x;
107
108 for (x = MAX_COLLISIONS - 1; x > 0; x--) {
109 keys[x] = keys[x - 1];
110 values[x] = values[x - 1];
111 }
112 keys[0] = key;
113 values[0] = value;
114}
115
116#ifndef CONFIG_PREEMPT_RT_FULL
117static void translate_buffer_write_args(int cpu, struct task_struct *task, const char *text)
118{
119 unsigned long flags;
120 int write;
121 int next_write;
122 struct cookie_args *args;
123
124 local_irq_save(flags);
125
126 write = per_cpu(translate_buffer_write, cpu);
127 next_write = (write + 1) & translate_buffer_mask;
128
129 // At least one entry must always remain available as when read == write, the queue is empty not full
130 if (next_write != per_cpu(translate_buffer_read, cpu)) {
131 args = &per_cpu(translate_buffer, cpu)[write];
132 args->task = task;
133 args->text = text;
134#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
135 get_task_struct(task);
136#endif
137 per_cpu(translate_buffer_write, cpu) = next_write;
138 }
139
140 local_irq_restore(flags);
141}
142#endif
143
144static void translate_buffer_read_args(int cpu, struct cookie_args *args)
145{
146 unsigned long flags;
147 int read;
148
149 local_irq_save(flags);
150
151 read = per_cpu(translate_buffer_read, cpu);
152 *args = per_cpu(translate_buffer, cpu)[read];
153 per_cpu(translate_buffer_read, cpu) = (read + 1) & translate_buffer_mask;
154
155 local_irq_restore(flags);
156}
157
158static void wq_cookie_handler(struct work_struct *unused)
159{
160 struct cookie_args args;
161 int cpu = get_physical_cpu(), cookie;
162
163 mutex_lock(&start_mutex);
164
165 if (gator_started != 0) {
166 while (per_cpu(translate_buffer_read, cpu) != per_cpu(translate_buffer_write, cpu)) {
167 translate_buffer_read_args(cpu, &args);
168 cookie = get_cookie(cpu, args.task, args.text, true);
169 marshal_link(cookie, args.task->tgid, args.task->pid);
170#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
171 put_task_struct(args.task);
172#endif
173 }
174 }
175
176 mutex_unlock(&start_mutex);
177}
178
179static void app_process_wake_up_handler(unsigned long unused_data)
180{
181 // had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater
182 schedule_work(&cookie_work);
183}
184
185// Retrieve full name from proc/pid/cmdline for java processes on Android
186static int translate_app_process(const char **text, int cpu, struct task_struct *task, bool from_wq)
187{
188 void *maddr;
189 unsigned int len;
190 unsigned long addr;
191 struct mm_struct *mm;
192 struct page *page = NULL;
193 struct vm_area_struct *page_vma;
194 int bytes, offset, retval = 0;
195 char *buf = per_cpu(translate_text, cpu);
196
197#ifndef CONFIG_PREEMPT_RT_FULL
198 // Push work into a work queue if in atomic context as the kernel functions below might sleep
199 // Rely on the in_interrupt variable rather than in_irq() or in_interrupt() kernel functions, as the value of these functions seems
200 // inconsistent during a context switch between android/linux versions
201 if (!from_wq) {
202 // Check if already in buffer
203 int pos = per_cpu(translate_buffer_read, cpu);
204 while (pos != per_cpu(translate_buffer_write, cpu)) {
205 if (per_cpu(translate_buffer, cpu)[pos].task == task)
206 goto out;
207 pos = (pos + 1) & translate_buffer_mask;
208 }
209
210 translate_buffer_write_args(cpu, task, *text);
211
212 // Not safe to call in RT-Preempt full in schedule switch context
213 mod_timer(&app_process_wake_up_timer, jiffies + 1);
214 goto out;
215 }
216#endif
217
218 mm = get_task_mm(task);
219 if (!mm)
220 goto out;
221 if (!mm->arg_end)
222 goto outmm;
223 addr = mm->arg_start;
224 len = mm->arg_end - mm->arg_start;
225
226 if (len > TRANSLATE_TEXT_SIZE)
227 len = TRANSLATE_TEXT_SIZE;
228
229 down_read(&mm->mmap_sem);
230 while (len) {
231 if (get_user_pages(task, mm, addr, 1, 0, 1, &page, &page_vma) <= 0)
232 goto outsem;
233
234 maddr = kmap(page);
235 offset = addr & (PAGE_SIZE - 1);
236 bytes = len;
237 if (bytes > PAGE_SIZE - offset)
238 bytes = PAGE_SIZE - offset;
239
240 copy_from_user_page(page_vma, page, addr, buf, maddr + offset, bytes);
241
242 kunmap(page); // release page allocated by get_user_pages()
243 page_cache_release(page);
244
245 len -= bytes;
246 buf += bytes;
247 addr += bytes;
248
249 *text = per_cpu(translate_text, cpu);
250 retval = 1;
251 }
252
253 // On app_process startup, /proc/pid/cmdline is initially "zygote" then "<pre-initialized>" but changes after an initial startup period
254 if (strcmp(*text, "zygote") == 0 || strcmp(*text, "<pre-initialized>") == 0)
255 retval = 0;
256
257outsem:
258 up_read(&mm->mmap_sem);
259outmm:
260 mmput(mm);
261out:
262 return retval;
263}
264
265static uint32_t get_cookie(int cpu, struct task_struct *task, const char *text, bool from_wq)
266{
267 unsigned long flags, cookie;
268 uint64_t key;
269
270 key = gator_chksum_crc32(text);
271 key = (key << 32) | (uint32_t)task->tgid;
272
273 cookie = cookiemap_exists(key);
274 if (cookie) {
275 return cookie;
276 }
277
278 if (strcmp(text, "app_process") == 0) {
279 if (!translate_app_process(&text, cpu, task, from_wq))
280 return UNRESOLVED_COOKIE;
281 }
282
283 // Can be called from interrupt handler or from work queue or from scheduler trace
284 local_irq_save(flags);
285
286 cookie = UNRESOLVED_COOKIE;
287 if (marshal_cookie_header(text)) {
288 cookie = per_cpu(cookie_next_key, cpu) += nr_cpu_ids;
289 cookiemap_add(key, cookie);
290 marshal_cookie(cookie, text);
291 }
292
293 local_irq_restore(flags);
294
295 return cookie;
296}
297
298static int get_exec_cookie(int cpu, struct task_struct *task)
299{
300 struct mm_struct *mm = task->mm;
301 const char *text;
302
303 // kernel threads have no address space
304 if (!mm)
305 return NO_COOKIE;
306
307 if (task && task->mm && task->mm->exe_file) {
308 text = task->mm->exe_file->f_path.dentry->d_name.name;
309 return get_cookie(cpu, task, text, false);
310 }
311
312 return UNRESOLVED_COOKIE;
313}
314
315static unsigned long get_address_cookie(int cpu, struct task_struct *task, unsigned long addr, off_t *offset)
316{
317 unsigned long cookie = NO_COOKIE;
318 struct mm_struct *mm = task->mm;
319 struct vm_area_struct *vma;
320 const char *text;
321
322 if (!mm)
323 return cookie;
324
325 for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) {
326 if (addr < vma->vm_start || addr >= vma->vm_end)
327 continue;
328
329 if (vma->vm_file) {
330 text = vma->vm_file->f_path.dentry->d_name.name;
331 cookie = get_cookie(cpu, task, text, false);
332 *offset = (vma->vm_pgoff << PAGE_SHIFT) + addr - vma->vm_start;
333 } else {
334 /* must be an anonymous map */
335 *offset = addr;
336 }
337
338 break;
339 }
340
341 if (!vma)
342 cookie = UNRESOLVED_COOKIE;
343
344 return cookie;
345}
346
347static int cookies_initialize(void)
348{
349 uint32_t crc, poly;
350 int i, j, cpu, size, err = 0;
351
352 translate_buffer_mask = TRANSLATE_BUFFER_SIZE / sizeof(per_cpu(translate_buffer, 0)[0]) - 1;
353
354 for_each_present_cpu(cpu) {
355 per_cpu(cookie_next_key, cpu) = nr_cpu_ids + cpu;
356
357 size = COOKIEMAP_ENTRIES * MAX_COLLISIONS * sizeof(uint64_t);
358 per_cpu(cookie_keys, cpu) = (uint64_t *)kmalloc(size, GFP_KERNEL);
359 if (!per_cpu(cookie_keys, cpu)) {
360 err = -ENOMEM;
361 goto cookie_setup_error;
362 }
363 memset(per_cpu(cookie_keys, cpu), 0, size);
364
365 size = COOKIEMAP_ENTRIES * MAX_COLLISIONS * sizeof(uint32_t);
366 per_cpu(cookie_values, cpu) = (uint32_t *)kmalloc(size, GFP_KERNEL);
367 if (!per_cpu(cookie_values, cpu)) {
368 err = -ENOMEM;
369 goto cookie_setup_error;
370 }
371 memset(per_cpu(cookie_values, cpu), 0, size);
372
373 per_cpu(translate_buffer, cpu) = (struct cookie_args *)kmalloc(TRANSLATE_BUFFER_SIZE, GFP_KERNEL);
374 if (!per_cpu(translate_buffer, cpu)) {
375 err = -ENOMEM;
376 goto cookie_setup_error;
377 }
378
379 per_cpu(translate_buffer_write, cpu) = 0;
380 per_cpu(translate_buffer_read, cpu) = 0;
381
382 per_cpu(translate_text, cpu) = (char *)kmalloc(TRANSLATE_TEXT_SIZE, GFP_KERNEL);
383 if (!per_cpu(translate_text, cpu)) {
384 err = -ENOMEM;
385 goto cookie_setup_error;
386 }
387 }
388
389 // build CRC32 table
390 poly = 0x04c11db7;
391 gator_crc32_table = (uint32_t *)kmalloc(256 * sizeof(uint32_t), GFP_KERNEL);
392 if (!gator_crc32_table) {
393 err = -ENOMEM;
394 goto cookie_setup_error;
395 }
396 for (i = 0; i < 256; i++) {
397 crc = i;
398 for (j = 8; j > 0; j--) {
399 if (crc & 1) {
400 crc = (crc >> 1) ^ poly;
401 } else {
402 crc >>= 1;
403 }
404 }
405 gator_crc32_table[i] = crc;
406 }
407
408 setup_timer(&app_process_wake_up_timer, app_process_wake_up_handler, 0);
409
410cookie_setup_error:
411 return err;
412}
413
414static void cookies_release(void)
415{
416 int cpu;
417
418 for_each_present_cpu(cpu) {
419 kfree(per_cpu(cookie_keys, cpu));
420 per_cpu(cookie_keys, cpu) = NULL;
421
422 kfree(per_cpu(cookie_values, cpu));
423 per_cpu(cookie_values, cpu) = NULL;
424
425 kfree(per_cpu(translate_buffer, cpu));
426 per_cpu(translate_buffer, cpu) = NULL;
427 per_cpu(translate_buffer_read, cpu) = 0;
428 per_cpu(translate_buffer_write, cpu) = 0;
429
430 kfree(per_cpu(translate_text, cpu));
431 per_cpu(translate_text, cpu) = NULL;
432 }
433
434 del_timer_sync(&app_process_wake_up_timer);
435 kfree(gator_crc32_table);
436 gator_crc32_table = NULL;
437}
diff --git a/drivers/gator/gator_events_armv6.c b/drivers/gator/gator_events_armv6.c
new file mode 100644
index 00000000000..35364562230
--- /dev/null
+++ b/drivers/gator/gator_events_armv6.c
@@ -0,0 +1,237 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "gator.h"
10
11// gator_events_perf_pmu.c is used if perf is supported
12#if GATOR_NO_PERF_SUPPORT
13
14static const char *pmnc_name;
15
16/*
17 * Per-CPU PMCR
18 */
19#define PMCR_E (1 << 0) /* Enable */
20#define PMCR_P (1 << 1) /* Count reset */
21#define PMCR_C (1 << 2) /* Cycle counter reset */
22#define PMCR_OFL_PMN0 (1 << 8) /* Count reg 0 overflow */
23#define PMCR_OFL_PMN1 (1 << 9) /* Count reg 1 overflow */
24#define PMCR_OFL_CCNT (1 << 10) /* Cycle counter overflow */
25
26#define PMN0 0
27#define PMN1 1
28#define CCNT 2
29#define CNTMAX (CCNT+1)
30
31static int pmnc_counters = 0;
32static unsigned long pmnc_enabled[CNTMAX];
33static unsigned long pmnc_event[CNTMAX];
34static unsigned long pmnc_key[CNTMAX];
35
36static DEFINE_PER_CPU(int[CNTMAX * 2], perfCnt);
37
38static inline void armv6_pmnc_write(u32 val)
39{
40 /* upper 4bits and 7, 11 are write-as-0 */
41 val &= 0x0ffff77f;
42 asm volatile("mcr p15, 0, %0, c15, c12, 0" : : "r" (val));
43}
44
45static inline u32 armv6_pmnc_read(void)
46{
47 u32 val;
48 asm volatile("mrc p15, 0, %0, c15, c12, 0" : "=r" (val));
49 return val;
50}
51
52static void armv6_pmnc_reset_counter(unsigned int cnt)
53{
54 u32 val = 0;
55 switch (cnt) {
56 case CCNT:
57 asm volatile("mcr p15, 0, %0, c15, c12, 1" : : "r" (val));
58 break;
59 case PMN0:
60 asm volatile("mcr p15, 0, %0, c15, c12, 2" : : "r" (val));
61 break;
62 case PMN1:
63 asm volatile("mcr p15, 0, %0, c15, c12, 3" : : "r" (val));
64 break;
65 }
66}
67
68int gator_events_armv6_create_files(struct super_block *sb, struct dentry *root)
69{
70 struct dentry *dir;
71 int i;
72
73 pmnc_counters = 3;
74
75 for (i = PMN0; i <= CCNT; i++) {
76 char buf[40];
77 if (i == CCNT) {
78 snprintf(buf, sizeof buf, "ARM_%s_ccnt", pmnc_name);
79 } else {
80 snprintf(buf, sizeof buf, "ARM_%s_cnt%d", pmnc_name, i);
81 }
82 dir = gatorfs_mkdir(sb, root, buf);
83 if (!dir) {
84 return -1;
85 }
86 gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]);
87 gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]);
88 if (i != CCNT) {
89 gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]);
90 }
91 }
92
93 return 0;
94}
95
96static int gator_events_armv6_online(int **buffer, bool migrate)
97{
98 unsigned int cnt, len = 0, cpu = smp_processor_id();
99 u32 pmnc;
100
101 if (armv6_pmnc_read() & PMCR_E) {
102 armv6_pmnc_write(armv6_pmnc_read() & ~PMCR_E);
103 }
104
105 /* initialize PMNC, reset overflow, D bit, C bit and P bit. */
106 armv6_pmnc_write(PMCR_OFL_PMN0 | PMCR_OFL_PMN1 | PMCR_OFL_CCNT |
107 PMCR_C | PMCR_P);
108
109 /* configure control register */
110 for (pmnc = 0, cnt = PMN0; cnt <= CCNT; cnt++) {
111 unsigned long event;
112
113 if (!pmnc_enabled[cnt])
114 continue;
115
116 event = pmnc_event[cnt] & 255;
117
118 // Set event (if destined for PMNx counters)
119 if (cnt == PMN0) {
120 pmnc |= event << 20;
121 } else if (cnt == PMN1) {
122 pmnc |= event << 12;
123 }
124
125 // Reset counter
126 armv6_pmnc_reset_counter(cnt);
127 }
128 armv6_pmnc_write(pmnc | PMCR_E);
129
130 // return zero values, no need to read as the counters were just reset
131 for (cnt = PMN0; cnt <= CCNT; cnt++) {
132 if (pmnc_enabled[cnt]) {
133 per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
134 per_cpu(perfCnt, cpu)[len++] = 0;
135 }
136 }
137
138 if (buffer)
139 *buffer = per_cpu(perfCnt, cpu);
140
141 return len;
142}
143
144static int gator_events_armv6_offline(int **buffer, bool migrate)
145{
146 unsigned int cnt;
147
148 armv6_pmnc_write(armv6_pmnc_read() & ~PMCR_E);
149 for (cnt = PMN0; cnt <= CCNT; cnt++) {
150 armv6_pmnc_reset_counter(cnt);
151 }
152
153 return 0;
154}
155
156static void gator_events_armv6_stop(void)
157{
158 unsigned int cnt;
159
160 for (cnt = PMN0; cnt <= CCNT; cnt++) {
161 pmnc_enabled[cnt] = 0;
162 pmnc_event[cnt] = 0;
163 }
164}
165
166static int gator_events_armv6_read(int **buffer)
167{
168 int cnt, len = 0;
169 int cpu = smp_processor_id();
170
171 // a context switch may occur before the online hotplug event, thus need to check that the pmu is enabled
172 if (!(armv6_pmnc_read() & PMCR_E)) {
173 return 0;
174 }
175
176 for (cnt = PMN0; cnt <= CCNT; cnt++) {
177 if (pmnc_enabled[cnt]) {
178 u32 value = 0;
179 switch (cnt) {
180 case CCNT:
181 asm volatile("mrc p15, 0, %0, c15, c12, 1" : "=r" (value));
182 break;
183 case PMN0:
184 asm volatile("mrc p15, 0, %0, c15, c12, 2" : "=r" (value));
185 break;
186 case PMN1:
187 asm volatile("mrc p15, 0, %0, c15, c12, 3" : "=r" (value));
188 break;
189 }
190 armv6_pmnc_reset_counter(cnt);
191
192 per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
193 per_cpu(perfCnt, cpu)[len++] = value;
194 }
195 }
196
197 if (buffer)
198 *buffer = per_cpu(perfCnt, cpu);
199
200 return len;
201}
202
203static struct gator_interface gator_events_armv6_interface = {
204 .create_files = gator_events_armv6_create_files,
205 .stop = gator_events_armv6_stop,
206 .online = gator_events_armv6_online,
207 .offline = gator_events_armv6_offline,
208 .read = gator_events_armv6_read,
209};
210
211int gator_events_armv6_init(void)
212{
213 unsigned int cnt;
214
215 switch (gator_cpuid()) {
216 case ARM1136:
217 case ARM1156:
218 case ARM1176:
219 pmnc_name = "ARM11";
220 break;
221 case ARM11MPCORE:
222 pmnc_name = "ARM11MPCore";
223 break;
224 default:
225 return -1;
226 }
227
228 for (cnt = PMN0; cnt <= CCNT; cnt++) {
229 pmnc_enabled[cnt] = 0;
230 pmnc_event[cnt] = 0;
231 pmnc_key[cnt] = gator_events_get_key();
232 }
233
234 return gator_events_install(&gator_events_armv6_interface);
235}
236
237#endif
diff --git a/drivers/gator/gator_events_armv7.c b/drivers/gator/gator_events_armv7.c
new file mode 100644
index 00000000000..bd8a9ba24e9
--- /dev/null
+++ b/drivers/gator/gator_events_armv7.c
@@ -0,0 +1,314 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9/* Disabling interrupts
10 * Many of the functions below disable interrupts via local_irq_save(). This disabling of interrupts is done to prevent any race conditions
11 * between multiple entities (e.g. hrtimer interrupts and event based interrupts) calling the same functions. As accessing the pmu involves
12 * several steps (disable, select, read, enable), these steps must be performed atomically. Normal synchronization routines cannot be used
13 * as these functions are being called from interrupt context.
14 */
15
16#include "gator.h"
17
18// gator_events_perf_pmu.c is used if perf is supported
19#if GATOR_NO_PERF_SUPPORT
20
21// Per-CPU PMNC: config reg
22#define PMNC_E (1 << 0) /* Enable all counters */
23#define PMNC_P (1 << 1) /* Reset all counters */
24#define PMNC_C (1 << 2) /* Cycle counter reset */
25#define PMNC_MASK 0x3f /* Mask for writable bits */
26
27// ccnt reg
28#define CCNT_REG (1 << 31)
29
30#define CCNT 0
31#define CNT0 1
32#define CNTMAX (6+1)
33
34static const char *pmnc_name;
35static int pmnc_counters;
36
37static unsigned long pmnc_enabled[CNTMAX];
38static unsigned long pmnc_event[CNTMAX];
39static unsigned long pmnc_key[CNTMAX];
40
41static DEFINE_PER_CPU(int[CNTMAX * 2], perfCnt);
42
43inline void armv7_pmnc_write(u32 val)
44{
45 val &= PMNC_MASK;
46 asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r" (val));
47}
48
49inline u32 armv7_pmnc_read(void)
50{
51 u32 val;
52 asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val));
53 return val;
54}
55
56inline u32 armv7_ccnt_read(u32 reset_value)
57{
58 unsigned long flags;
59 u32 newval = -reset_value;
60 u32 den = CCNT_REG;
61 u32 val;
62
63 local_irq_save(flags);
64 asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (den)); // disable
65 asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val)); // read
66 asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (newval)); // new value
67 asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (den)); // enable
68 local_irq_restore(flags);
69
70 return val;
71}
72
73inline u32 armv7_cntn_read(unsigned int cnt, u32 reset_value)
74{
75 unsigned long flags;
76 u32 newval = -reset_value;
77 u32 sel = (cnt - CNT0);
78 u32 den = 1 << sel;
79 u32 oldval;
80
81 local_irq_save(flags);
82 asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (den)); // disable
83 asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (sel)); // select
84 asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (oldval)); // read
85 asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (newval)); // new value
86 asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (den)); // enable
87 local_irq_restore(flags);
88
89 return oldval;
90}
91
92static inline void armv7_pmnc_disable_interrupt(unsigned int cnt)
93{
94 u32 val = cnt ? (1 << (cnt - CNT0)) : (1 << 31);
95 asm volatile("mcr p15, 0, %0, c9, c14, 2" : : "r" (val));
96}
97
98inline u32 armv7_pmnc_reset_interrupt(void)
99{
100 // Get and reset overflow status flags
101 u32 flags;
102 asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (flags));
103 flags &= 0x8000003f;
104 asm volatile("mcr p15, 0, %0, c9, c12, 3" : : "r" (flags));
105 return flags;
106}
107
108static inline u32 armv7_pmnc_enable_counter(unsigned int cnt)
109{
110 u32 val = cnt ? (1 << (cnt - CNT0)) : CCNT_REG;
111 asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val));
112 return cnt;
113}
114
115static inline u32 armv7_pmnc_disable_counter(unsigned int cnt)
116{
117 u32 val = cnt ? (1 << (cnt - CNT0)) : CCNT_REG;
118 asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val));
119 return cnt;
120}
121
122static inline int armv7_pmnc_select_counter(unsigned int cnt)
123{
124 u32 val = (cnt - CNT0);
125 asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val));
126 return cnt;
127}
128
129static inline void armv7_pmnc_write_evtsel(unsigned int cnt, u32 val)
130{
131 if (armv7_pmnc_select_counter(cnt) == cnt) {
132 asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val));
133 }
134}
135
136static int gator_events_armv7_create_files(struct super_block *sb, struct dentry *root)
137{
138 struct dentry *dir;
139 int i;
140
141 for (i = 0; i < pmnc_counters; i++) {
142 char buf[40];
143 if (i == 0) {
144 snprintf(buf, sizeof buf, "%s_ccnt", pmnc_name);
145 } else {
146 snprintf(buf, sizeof buf, "%s_cnt%d", pmnc_name, i - 1);
147 }
148 dir = gatorfs_mkdir(sb, root, buf);
149 if (!dir) {
150 return -1;
151 }
152 gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]);
153 gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]);
154 if (i > 0) {
155 gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]);
156 }
157 }
158
159 return 0;
160}
161
162static int gator_events_armv7_online(int **buffer, bool migrate)
163{
164 unsigned int cnt, len = 0, cpu = smp_processor_id();
165
166 if (armv7_pmnc_read() & PMNC_E) {
167 armv7_pmnc_write(armv7_pmnc_read() & ~PMNC_E);
168 }
169
170 // Initialize & Reset PMNC: C bit and P bit
171 armv7_pmnc_write(PMNC_P | PMNC_C);
172
173 // Reset overflow flags
174 armv7_pmnc_reset_interrupt();
175
176 for (cnt = CCNT; cnt < CNTMAX; cnt++) {
177 unsigned long event;
178
179 if (!pmnc_enabled[cnt])
180 continue;
181
182 // Disable counter
183 armv7_pmnc_disable_counter(cnt);
184
185 event = pmnc_event[cnt] & 255;
186
187 // Set event (if destined for PMNx counters), we don't need to set the event if it's a cycle count
188 if (cnt != CCNT)
189 armv7_pmnc_write_evtsel(cnt, event);
190
191 armv7_pmnc_disable_interrupt(cnt);
192
193 // Reset counter
194 cnt ? armv7_cntn_read(cnt, 0) : armv7_ccnt_read(0);
195
196 // Enable counter
197 armv7_pmnc_enable_counter(cnt);
198 }
199
200 // enable
201 armv7_pmnc_write(armv7_pmnc_read() | PMNC_E);
202
203 // return zero values, no need to read as the counters were just reset
204 for (cnt = 0; cnt < pmnc_counters; cnt++) {
205 if (pmnc_enabled[cnt]) {
206 per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
207 per_cpu(perfCnt, cpu)[len++] = 0;
208 }
209 }
210
211 if (buffer)
212 *buffer = per_cpu(perfCnt, cpu);
213
214 return len;
215}
216
217static int gator_events_armv7_offline(int **buffer, bool migrate)
218{
219 // disable all counters, including PMCCNTR; overflow IRQs will not be signaled
220 armv7_pmnc_write(armv7_pmnc_read() & ~PMNC_E);
221
222 return 0;
223}
224
225static void gator_events_armv7_stop(void)
226{
227 unsigned int cnt;
228
229 for (cnt = CCNT; cnt < CNTMAX; cnt++) {
230 pmnc_enabled[cnt] = 0;
231 pmnc_event[cnt] = 0;
232 }
233}
234
235static int gator_events_armv7_read(int **buffer)
236{
237 int cnt, len = 0;
238 int cpu = smp_processor_id();
239
240 // a context switch may occur before the online hotplug event, thus need to check that the pmu is enabled
241 if (!(armv7_pmnc_read() & PMNC_E)) {
242 return 0;
243 }
244
245 for (cnt = 0; cnt < pmnc_counters; cnt++) {
246 if (pmnc_enabled[cnt]) {
247 int value;
248 if (cnt == CCNT) {
249 value = armv7_ccnt_read(0);
250 } else {
251 value = armv7_cntn_read(cnt, 0);
252 }
253 per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
254 per_cpu(perfCnt, cpu)[len++] = value;
255 }
256 }
257
258 if (buffer)
259 *buffer = per_cpu(perfCnt, cpu);
260
261 return len;
262}
263
264static struct gator_interface gator_events_armv7_interface = {
265 .create_files = gator_events_armv7_create_files,
266 .stop = gator_events_armv7_stop,
267 .online = gator_events_armv7_online,
268 .offline = gator_events_armv7_offline,
269 .read = gator_events_armv7_read,
270};
271
272int gator_events_armv7_init(void)
273{
274 unsigned int cnt;
275
276 switch (gator_cpuid()) {
277 case CORTEX_A5:
278 pmnc_name = "ARMv7_Cortex_A5";
279 pmnc_counters = 2;
280 break;
281 case CORTEX_A7:
282 pmnc_name = "ARMv7_Cortex_A7";
283 pmnc_counters = 4;
284 break;
285 case CORTEX_A8:
286 pmnc_name = "ARMv7_Cortex_A8";
287 pmnc_counters = 4;
288 break;
289 case CORTEX_A9:
290 pmnc_name = "ARMv7_Cortex_A9";
291 pmnc_counters = 6;
292 break;
293 // ARM Cortex A12 is not supported by version of Linux before 3.0
294 case CORTEX_A15:
295 pmnc_name = "ARMv7_Cortex_A15";
296 pmnc_counters = 6;
297 break;
298 // ARM Cortex A17 is not supported by version of Linux before 3.0
299 default:
300 return -1;
301 }
302
303 pmnc_counters++; // CNT[n] + CCNT
304
305 for (cnt = CCNT; cnt < CNTMAX; cnt++) {
306 pmnc_enabled[cnt] = 0;
307 pmnc_event[cnt] = 0;
308 pmnc_key[cnt] = gator_events_get_key();
309 }
310
311 return gator_events_install(&gator_events_armv7_interface);
312}
313
314#endif
diff --git a/drivers/gator/gator_events_block.c b/drivers/gator/gator_events_block.c
new file mode 100644
index 00000000000..03eed4fb9eb
--- /dev/null
+++ b/drivers/gator/gator_events_block.c
@@ -0,0 +1,163 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10#include "gator.h"
11#include <trace/events/block.h>
12
13#define BLOCK_RQ_WR 0
14#define BLOCK_RQ_RD 1
15
16#define BLOCK_TOTAL (BLOCK_RQ_RD+1)
17
18#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
19#define EVENTWRITE REQ_RW
20#else
21#define EVENTWRITE REQ_WRITE
22#endif
23
24static ulong block_rq_wr_enabled;
25static ulong block_rq_rd_enabled;
26static ulong block_rq_wr_key;
27static ulong block_rq_rd_key;
28static atomic_t blockCnt[BLOCK_TOTAL];
29static int blockGet[BLOCK_TOTAL * 4];
30
31// Tracepoint changed in 3.15 backported to older kernels. The Makefile tries to autodetect the correct value, but if it fails change the #if below
32#if OLD_BLOCK_RQ_COMPLETE
33GATOR_DEFINE_PROBE(block_rq_complete, TP_PROTO(struct request_queue *q, struct request *rq))
34#else
35GATOR_DEFINE_PROBE(block_rq_complete, TP_PROTO(struct request_queue *q, struct request *rq, unsigned int nr_bytes))
36#endif
37{
38 int write;
39 unsigned int size;
40
41 if (!rq)
42 return;
43
44 write = rq->cmd_flags & EVENTWRITE;
45#if OLD_BLOCK_RQ_COMPLETE
46 size = rq->resid_len;
47#else
48 size = nr_bytes;
49#endif
50
51 if (!size)
52 return;
53
54 if (write) {
55 if (block_rq_wr_enabled) {
56 atomic_add(size, &blockCnt[BLOCK_RQ_WR]);
57 }
58 } else {
59 if (block_rq_rd_enabled) {
60 atomic_add(size, &blockCnt[BLOCK_RQ_RD]);
61 }
62 }
63}
64
65static int gator_events_block_create_files(struct super_block *sb, struct dentry *root)
66{
67 struct dentry *dir;
68
69 /* block_complete_wr */
70 dir = gatorfs_mkdir(sb, root, "Linux_block_rq_wr");
71 if (!dir) {
72 return -1;
73 }
74 gatorfs_create_ulong(sb, dir, "enabled", &block_rq_wr_enabled);
75 gatorfs_create_ro_ulong(sb, dir, "key", &block_rq_wr_key);
76
77 /* block_complete_rd */
78 dir = gatorfs_mkdir(sb, root, "Linux_block_rq_rd");
79 if (!dir) {
80 return -1;
81 }
82 gatorfs_create_ulong(sb, dir, "enabled", &block_rq_rd_enabled);
83 gatorfs_create_ro_ulong(sb, dir, "key", &block_rq_rd_key);
84
85 return 0;
86}
87
88static int gator_events_block_start(void)
89{
90 // register tracepoints
91 if (block_rq_wr_enabled || block_rq_rd_enabled)
92 if (GATOR_REGISTER_TRACE(block_rq_complete))
93 goto fail_block_rq_exit;
94 pr_debug("gator: registered block event tracepoints\n");
95
96 return 0;
97
98 // unregister tracepoints on error
99fail_block_rq_exit:
100 pr_err("gator: block event tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n");
101
102 return -1;
103}
104
105static void gator_events_block_stop(void)
106{
107 if (block_rq_wr_enabled || block_rq_rd_enabled)
108 GATOR_UNREGISTER_TRACE(block_rq_complete);
109 pr_debug("gator: unregistered block event tracepoints\n");
110
111 block_rq_wr_enabled = 0;
112 block_rq_rd_enabled = 0;
113}
114
115static int gator_events_block_read(int **buffer)
116{
117 int len, value, data = 0;
118
119 if (!on_primary_core()) {
120 return 0;
121 }
122
123 len = 0;
124 if (block_rq_wr_enabled && (value = atomic_read(&blockCnt[BLOCK_RQ_WR])) > 0) {
125 atomic_sub(value, &blockCnt[BLOCK_RQ_WR]);
126 blockGet[len++] = block_rq_wr_key;
127 blockGet[len++] = 0; // indicates to Streamline that value bytes were written now, not since the last message
128 blockGet[len++] = block_rq_wr_key;
129 blockGet[len++] = value;
130 data += value;
131 }
132 if (block_rq_rd_enabled && (value = atomic_read(&blockCnt[BLOCK_RQ_RD])) > 0) {
133 atomic_sub(value, &blockCnt[BLOCK_RQ_RD]);
134 blockGet[len++] = block_rq_rd_key;
135 blockGet[len++] = 0; // indicates to Streamline that value bytes were read now, not since the last message
136 blockGet[len++] = block_rq_rd_key;
137 blockGet[len++] = value;
138 data += value;
139 }
140
141 if (buffer)
142 *buffer = blockGet;
143
144 return len;
145}
146
147static struct gator_interface gator_events_block_interface = {
148 .create_files = gator_events_block_create_files,
149 .start = gator_events_block_start,
150 .stop = gator_events_block_stop,
151 .read = gator_events_block_read,
152};
153
154int gator_events_block_init(void)
155{
156 block_rq_wr_enabled = 0;
157 block_rq_rd_enabled = 0;
158
159 block_rq_wr_key = gator_events_get_key();
160 block_rq_rd_key = gator_events_get_key();
161
162 return gator_events_install(&gator_events_block_interface);
163}
diff --git a/drivers/gator/gator_events_ccn-504.c b/drivers/gator/gator_events_ccn-504.c
new file mode 100644
index 00000000000..024ffc2856a
--- /dev/null
+++ b/drivers/gator/gator_events_ccn-504.c
@@ -0,0 +1,346 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include <linux/io.h>
10#include <linux/module.h>
11
12#include "gator.h"
13
14#define NUM_REGIONS 256
15#define REGION_SIZE (64*1024)
16#define REGION_DEBUG 1
17#define REGION_XP 64
18#define NUM_XPS 11
19
20// DT (Debug) region
21#define PMEVCNTSR0 0x0150
22#define PMCCNTRSR 0x0190
23#define PMCR 0x01A8
24#define PMSR 0x01B0
25#define PMSR_REQ 0x01B8
26#define PMSR_CLR 0x01C0
27
28// XP region
29#define DT_CONFIG 0x0300
30#define DT_CONTROL 0x0370
31
32// Multiple
33#define PMU_EVENT_SEL 0x0600
34#define OLY_ID 0xFF00
35
36#define CCNT 4
37#define CNTMAX (CCNT + 1)
38
39#define get_pmu_event_id(event) (((event) >> 0) & 0xFF)
40#define get_node_type(event) (((event) >> 8) & 0xFF)
41#define get_region(event) (((event) >> 16) & 0xFF)
42
43#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
44
45// From kernel/params.c
46#define STANDARD_PARAM_DEF(name, type, format, tmptype, strtolfn) \
47 int param_set_##name(const char *val, struct kernel_param *kp) \
48 { \
49 tmptype l; \
50 int ret; \
51 \
52 if (!val) return -EINVAL; \
53 ret = strtolfn(val, 0, &l); \
54 if (ret == -EINVAL || ((type)l != l)) \
55 return -EINVAL; \
56 *((type *)kp->arg) = l; \
57 return 0; \
58 } \
59 int param_get_##name(char *buffer, struct kernel_param *kp) \
60 { \
61 return sprintf(buffer, format, *((type *)kp->arg)); \
62 }
63
64#else
65
66// From kernel/params.c
67#define STANDARD_PARAM_DEF(name, type, format, tmptype, strtolfn) \
68 int param_set_##name(const char *val, const struct kernel_param *kp) \
69 { \
70 tmptype l; \
71 int ret; \
72 \
73 ret = strtolfn(val, 0, &l); \
74 if (ret < 0 || ((type)l != l)) \
75 return ret < 0 ? ret : -EINVAL; \
76 *((type *)kp->arg) = l; \
77 return 0; \
78 } \
79 int param_get_##name(char *buffer, const struct kernel_param *kp) \
80 { \
81 return scnprintf(buffer, PAGE_SIZE, format, \
82 *((type *)kp->arg)); \
83 } \
84 struct kernel_param_ops param_ops_##name = { \
85 .set = param_set_##name, \
86 .get = param_get_##name, \
87 }; \
88 EXPORT_SYMBOL(param_set_##name); \
89 EXPORT_SYMBOL(param_get_##name); \
90 EXPORT_SYMBOL(param_ops_##name)
91
92#endif
93
94STANDARD_PARAM_DEF(u64, u64, "%llu", u64, strict_strtoull);
95
96// From include/linux/moduleparam.h
97#define param_check_u64(name, p) __param_check(name, p, u64)
98
99MODULE_PARM_DESC(ccn504_addr, "CCN-504 physical base address");
100static u64 ccn504_addr = 0;
101module_param(ccn504_addr, u64, 0444);
102
103static void __iomem *gator_events_ccn504_base;
104static bool gator_events_ccn504_global_enabled;
105static unsigned long gator_events_ccn504_enabled[CNTMAX];
106static unsigned long gator_events_ccn504_event[CNTMAX];
107static unsigned long gator_events_ccn504_key[CNTMAX];
108static int gator_events_ccn504_buffer[2*CNTMAX];
109static int gator_events_ccn504_prev[CNTMAX];
110
111static void gator_events_ccn504_create_shutdown(void)
112{
113 if (gator_events_ccn504_base != NULL) {
114 iounmap(gator_events_ccn504_base);
115 }
116}
117
118static int gator_events_ccn504_create_files(struct super_block *sb, struct dentry *root)
119{
120 struct dentry *dir;
121 int i;
122 char buf[32];
123
124 for (i = 0; i < CNTMAX; ++i) {
125 if (i == CCNT) {
126 snprintf(buf, sizeof(buf), "CCN-504_ccnt");
127 } else {
128 snprintf(buf, sizeof(buf), "CCN-504_cnt%i", i);
129 }
130 dir = gatorfs_mkdir(sb, root, buf);
131 if (!dir) {
132 return -1;
133 }
134
135 gatorfs_create_ulong(sb, dir, "enabled", &gator_events_ccn504_enabled[i]);
136 if (i != CCNT) {
137 gatorfs_create_ulong(sb, dir, "event", &gator_events_ccn504_event[i]);
138 }
139 gatorfs_create_ro_ulong(sb, dir, "key", &gator_events_ccn504_key[i]);
140 }
141
142 return 0;
143}
144
145static void gator_events_ccn504_set_dt_config(int xp_node_id, int event_num, int value)
146{
147 u32 dt_config;
148
149 dt_config = readl(gator_events_ccn504_base + (REGION_XP + xp_node_id)*REGION_SIZE + DT_CONFIG);
150 dt_config |= (value + event_num) << (4*event_num);
151 writel(dt_config, gator_events_ccn504_base + (REGION_XP + xp_node_id)*REGION_SIZE + DT_CONFIG);
152}
153
154static int gator_events_ccn504_start(void)
155{
156 int i;
157
158 gator_events_ccn504_global_enabled = 0;
159 for (i = 0; i < CNTMAX; ++i) {
160 if (gator_events_ccn504_enabled[i]) {
161 gator_events_ccn504_global_enabled = 1;
162 break;
163 }
164 }
165
166 if (!gator_events_ccn504_global_enabled) {
167 return 0;
168 }
169
170 memset(&gator_events_ccn504_prev, 0x80, sizeof(gator_events_ccn504_prev));
171
172 // Disable INTREQ on overflow
173 // [6] ovfl_intr_en = 0
174 // perhaps set to 1?
175 // [5] cntr_rst = 0
176 // No register paring
177 // [4:1] cntcfg = 0
178 // Enable PMU features
179 // [0] pmu_en = 1
180 writel(0x1, gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMCR);
181
182 // Configure the XPs
183 for (i = 0; i < NUM_XPS; ++i) {
184 int dt_control;
185
186 // Pass on all events
187 writel(0, gator_events_ccn504_base + (REGION_XP + i)*REGION_SIZE + DT_CONFIG);
188
189 // Enable PMU capability
190 // [0] dt_enable = 1
191 dt_control = readl(gator_events_ccn504_base + (REGION_XP + i)*REGION_SIZE + DT_CONTROL);
192 dt_control |= 0x1;
193 writel(dt_control, gator_events_ccn504_base + (REGION_XP + i)*REGION_SIZE + DT_CONTROL);
194 }
195
196 // Assume no other pmu_event_sel registers are set
197
198 // cycle counter does not need to be enabled
199 for (i = 0; i < CCNT; ++i) {
200 int pmu_event_id;
201 int node_type;
202 int region;
203 u32 pmu_event_sel;
204 u32 oly_id_whole;
205 u32 oly_id;
206 u32 node_id;
207
208 if (!gator_events_ccn504_enabled[i]) {
209 continue;
210 }
211
212 pmu_event_id = get_pmu_event_id(gator_events_ccn504_event[i]);
213 node_type = get_node_type(gator_events_ccn504_event[i]);
214 region = get_region(gator_events_ccn504_event[i]);
215
216 // Verify the node_type
217 oly_id_whole = readl(gator_events_ccn504_base + region*REGION_SIZE + OLY_ID);
218 oly_id = oly_id_whole & 0x1F;
219 node_id = (oly_id_whole >> 8) & 0x7F;
220 if ((oly_id != node_type) ||
221 ((node_type == 0x16) && ((oly_id != 0x14) && (oly_id != 0x15) && (oly_id != 0x16) && (oly_id != 0x18) && (oly_id != 0x19) && (oly_id != 0x1A)))) {
222 printk(KERN_ERR "gator: oly_id is 0x%x expected 0x%x\n", oly_id, node_type);
223 return -1;
224 }
225
226 // Set the control register
227 pmu_event_sel = readl(gator_events_ccn504_base + region*REGION_SIZE + PMU_EVENT_SEL);
228 switch (node_type) {
229 case 0x08: // XP
230 pmu_event_sel |= pmu_event_id << (7*i);
231 gator_events_ccn504_set_dt_config(node_id, i, 0x4);
232 break;
233 case 0x04: // HN-F
234 case 0x16: // RN-I
235 case 0x10: // SBAS
236 pmu_event_sel |= pmu_event_id << (4*i);
237 gator_events_ccn504_set_dt_config(node_id/2, i, (node_id & 1) == 0 ? 0x8 : 0xC);
238 break;
239 }
240 writel(pmu_event_sel, gator_events_ccn504_base + region*REGION_SIZE + PMU_EVENT_SEL);
241 }
242
243 return 0;
244}
245
246static void gator_events_ccn504_stop(void)
247{
248 int i;
249
250 if (!gator_events_ccn504_global_enabled) {
251 return;
252 }
253
254 // cycle counter does not need to be disabled
255 for (i = 0; i < CCNT; ++i) {
256 int region;
257
258 if (!gator_events_ccn504_enabled[i]) {
259 continue;
260 }
261
262 region = get_region(gator_events_ccn504_event[i]);
263
264 writel(0, gator_events_ccn504_base + region*REGION_SIZE + PMU_EVENT_SEL);
265 }
266
267 // Clear dt_config
268 for (i = 0; i < NUM_XPS; ++i) {
269 writel(0, gator_events_ccn504_base + (REGION_XP + i)*REGION_SIZE + DT_CONFIG);
270 }
271}
272
273static int gator_events_ccn504_read(int **buffer)
274{
275 int i;
276 int len = 0;
277 int value;
278
279 if (!on_primary_core() || !gator_events_ccn504_global_enabled) {
280 return 0;
281 }
282
283 // Verify the pmsr register is zero
284 while (readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR) != 0);
285
286 // Request a PMU snapshot
287 writel(1, gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR_REQ);
288
289 // Wait for the snapshot
290 while (readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR) == 0);
291
292 // Read the shadow registers
293 for (i = 0; i < CNTMAX; ++i) {
294 if (!gator_events_ccn504_enabled[i]) {
295 continue;
296 }
297
298 value = readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + (i == CCNT ? PMCCNTRSR : PMEVCNTSR0 + 8*i));
299 if (gator_events_ccn504_prev[i] != 0x80808080) {
300 gator_events_ccn504_buffer[len++] = gator_events_ccn504_key[i];
301 gator_events_ccn504_buffer[len++] = value - gator_events_ccn504_prev[i];
302 }
303 gator_events_ccn504_prev[i] = value;
304
305 // Are the counters registers cleared when read? Is that what the cntr_rst bit on the pmcr register does?
306 }
307
308 // Clear the PMU snapshot status
309 writel(1, gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR_CLR);
310
311 if (buffer)
312 *buffer = gator_events_ccn504_buffer;
313
314 return len;
315}
316
317static struct gator_interface gator_events_ccn504_interface = {
318 .shutdown = gator_events_ccn504_create_shutdown,
319 .create_files = gator_events_ccn504_create_files,
320 .start = gator_events_ccn504_start,
321 .stop = gator_events_ccn504_stop,
322 .read = gator_events_ccn504_read,
323};
324
325int gator_events_ccn504_init(void)
326{
327 int i;
328
329 if (ccn504_addr == 0) {
330 return -1;
331 }
332
333 gator_events_ccn504_base = ioremap(ccn504_addr, NUM_REGIONS*REGION_SIZE);
334 if (gator_events_ccn504_base == NULL) {
335 printk(KERN_ERR "gator: ioremap returned NULL\n");
336 return -1;
337 }
338
339 for (i = 0; i < CNTMAX; ++i) {
340 gator_events_ccn504_enabled[i] = 0;
341 gator_events_ccn504_event[i] = 0;
342 gator_events_ccn504_key[i] = gator_events_get_key();
343 }
344
345 return gator_events_install(&gator_events_ccn504_interface);
346}
diff --git a/drivers/gator/gator_events_irq.c b/drivers/gator/gator_events_irq.c
new file mode 100644
index 00000000000..facbdd62325
--- /dev/null
+++ b/drivers/gator/gator_events_irq.c
@@ -0,0 +1,165 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10#include "gator.h"
11#include <trace/events/irq.h>
12
13#define HARDIRQ 0
14#define SOFTIRQ 1
15#define TOTALIRQ (SOFTIRQ+1)
16
17static ulong hardirq_enabled;
18static ulong softirq_enabled;
19static ulong hardirq_key;
20static ulong softirq_key;
21static DEFINE_PER_CPU(atomic_t[TOTALIRQ], irqCnt);
22static DEFINE_PER_CPU(int[TOTALIRQ * 2], irqGet);
23
24GATOR_DEFINE_PROBE(irq_handler_exit,
25 TP_PROTO(int irq, struct irqaction *action, int ret))
26{
27 atomic_inc(&per_cpu(irqCnt, get_physical_cpu())[HARDIRQ]);
28}
29
30#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37)
31GATOR_DEFINE_PROBE(softirq_exit, TP_PROTO(struct softirq_action *h, struct softirq_action *vec))
32#else
33GATOR_DEFINE_PROBE(softirq_exit, TP_PROTO(unsigned int vec_nr))
34#endif
35{
36 atomic_inc(&per_cpu(irqCnt, get_physical_cpu())[SOFTIRQ]);
37}
38
39static int gator_events_irq_create_files(struct super_block *sb, struct dentry *root)
40{
41 struct dentry *dir;
42
43 /* irq */
44 dir = gatorfs_mkdir(sb, root, "Linux_irq_irq");
45 if (!dir) {
46 return -1;
47 }
48 gatorfs_create_ulong(sb, dir, "enabled", &hardirq_enabled);
49 gatorfs_create_ro_ulong(sb, dir, "key", &hardirq_key);
50
51 /* soft irq */
52 dir = gatorfs_mkdir(sb, root, "Linux_irq_softirq");
53 if (!dir) {
54 return -1;
55 }
56 gatorfs_create_ulong(sb, dir, "enabled", &softirq_enabled);
57 gatorfs_create_ro_ulong(sb, dir, "key", &softirq_key);
58
59 return 0;
60}
61
62static int gator_events_irq_online(int **buffer, bool migrate)
63{
64 int len = 0, cpu = get_physical_cpu();
65
66 // synchronization with the irq_exit functions is not necessary as the values are being reset
67 if (hardirq_enabled) {
68 atomic_set(&per_cpu(irqCnt, cpu)[HARDIRQ], 0);
69 per_cpu(irqGet, cpu)[len++] = hardirq_key;
70 per_cpu(irqGet, cpu)[len++] = 0;
71 }
72
73 if (softirq_enabled) {
74 atomic_set(&per_cpu(irqCnt, cpu)[SOFTIRQ], 0);
75 per_cpu(irqGet, cpu)[len++] = softirq_key;
76 per_cpu(irqGet, cpu)[len++] = 0;
77 }
78
79 if (buffer)
80 *buffer = per_cpu(irqGet, cpu);
81
82 return len;
83}
84
85static int gator_events_irq_start(void)
86{
87 // register tracepoints
88 if (hardirq_enabled)
89 if (GATOR_REGISTER_TRACE(irq_handler_exit))
90 goto fail_hardirq_exit;
91 if (softirq_enabled)
92 if (GATOR_REGISTER_TRACE(softirq_exit))
93 goto fail_softirq_exit;
94 pr_debug("gator: registered irq tracepoints\n");
95
96 return 0;
97
98 // unregister tracepoints on error
99fail_softirq_exit:
100 if (hardirq_enabled)
101 GATOR_UNREGISTER_TRACE(irq_handler_exit);
102fail_hardirq_exit:
103 pr_err("gator: irq tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n");
104
105 return -1;
106}
107
108static void gator_events_irq_stop(void)
109{
110 if (hardirq_enabled)
111 GATOR_UNREGISTER_TRACE(irq_handler_exit);
112 if (softirq_enabled)
113 GATOR_UNREGISTER_TRACE(softirq_exit);
114 pr_debug("gator: unregistered irq tracepoints\n");
115
116 hardirq_enabled = 0;
117 softirq_enabled = 0;
118}
119
120static int gator_events_irq_read(int **buffer)
121{
122 int len, value;
123 int cpu = get_physical_cpu();
124
125 len = 0;
126 if (hardirq_enabled) {
127 value = atomic_read(&per_cpu(irqCnt, cpu)[HARDIRQ]);
128 atomic_sub(value, &per_cpu(irqCnt, cpu)[HARDIRQ]);
129
130 per_cpu(irqGet, cpu)[len++] = hardirq_key;
131 per_cpu(irqGet, cpu)[len++] = value;
132 }
133
134 if (softirq_enabled) {
135 value = atomic_read(&per_cpu(irqCnt, cpu)[SOFTIRQ]);
136 atomic_sub(value, &per_cpu(irqCnt, cpu)[SOFTIRQ]);
137
138 per_cpu(irqGet, cpu)[len++] = softirq_key;
139 per_cpu(irqGet, cpu)[len++] = value;
140 }
141
142 if (buffer)
143 *buffer = per_cpu(irqGet, cpu);
144
145 return len;
146}
147
148static struct gator_interface gator_events_irq_interface = {
149 .create_files = gator_events_irq_create_files,
150 .online = gator_events_irq_online,
151 .start = gator_events_irq_start,
152 .stop = gator_events_irq_stop,
153 .read = gator_events_irq_read,
154};
155
156int gator_events_irq_init(void)
157{
158 hardirq_key = gator_events_get_key();
159 softirq_key = gator_events_get_key();
160
161 hardirq_enabled = 0;
162 softirq_enabled = 0;
163
164 return gator_events_install(&gator_events_irq_interface);
165}
diff --git a/drivers/gator/gator_events_l2c-310.c b/drivers/gator/gator_events_l2c-310.c
new file mode 100644
index 00000000000..553f9707bdb
--- /dev/null
+++ b/drivers/gator/gator_events_l2c-310.c
@@ -0,0 +1,208 @@
1/**
2 * l2c310 (L2 Cache Controller) event counters for gator
3 *
4 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/init.h>
12#include <linux/io.h>
13#include <linux/module.h>
14#if defined(CONFIG_OF)
15#include <linux/of.h>
16#include <linux/of_address.h>
17#endif
18#include <asm/hardware/cache-l2x0.h>
19
20#include "gator.h"
21
22#define L2C310_COUNTERS_NUM 2
23
24static struct {
25 unsigned long enabled;
26 unsigned long event;
27 unsigned long key;
28} l2c310_counters[L2C310_COUNTERS_NUM];
29
30static int l2c310_buffer[L2C310_COUNTERS_NUM * 2];
31
32static void __iomem *l2c310_base;
33
34static void gator_events_l2c310_reset_counters(void)
35{
36 u32 val = readl(l2c310_base + L2X0_EVENT_CNT_CTRL);
37
38 val |= ((1 << L2C310_COUNTERS_NUM) - 1) << 1;
39
40 writel(val, l2c310_base + L2X0_EVENT_CNT_CTRL);
41}
42
43static int gator_events_l2c310_create_files(struct super_block *sb,
44 struct dentry *root)
45{
46 int i;
47
48 for (i = 0; i < L2C310_COUNTERS_NUM; i++) {
49 char buf[16];
50 struct dentry *dir;
51
52 snprintf(buf, sizeof(buf), "L2C-310_cnt%d", i);
53 dir = gatorfs_mkdir(sb, root, buf);
54 if (WARN_ON(!dir))
55 return -1;
56 gatorfs_create_ulong(sb, dir, "enabled",
57 &l2c310_counters[i].enabled);
58 gatorfs_create_ulong(sb, dir, "event",
59 &l2c310_counters[i].event);
60 gatorfs_create_ro_ulong(sb, dir, "key",
61 &l2c310_counters[i].key);
62 }
63
64 return 0;
65}
66
67static int gator_events_l2c310_start(void)
68{
69 static const unsigned long l2x0_event_cntx_cfg[L2C310_COUNTERS_NUM] = {
70 L2X0_EVENT_CNT0_CFG,
71 L2X0_EVENT_CNT1_CFG,
72 };
73 int i;
74
75 /* Counter event sources */
76 for (i = 0; i < L2C310_COUNTERS_NUM; i++)
77 writel((l2c310_counters[i].event & 0xf) << 2,
78 l2c310_base + l2x0_event_cntx_cfg[i]);
79
80 gator_events_l2c310_reset_counters();
81
82 /* Event counter enable */
83 writel(1, l2c310_base + L2X0_EVENT_CNT_CTRL);
84
85 return 0;
86}
87
88static void gator_events_l2c310_stop(void)
89{
90 /* Event counter disable */
91 writel(0, l2c310_base + L2X0_EVENT_CNT_CTRL);
92}
93
94static int gator_events_l2c310_read(int **buffer)
95{
96 static const unsigned long l2x0_event_cntx_val[L2C310_COUNTERS_NUM] = {
97 L2X0_EVENT_CNT0_VAL,
98 L2X0_EVENT_CNT1_VAL,
99 };
100 int i;
101 int len = 0;
102
103 if (!on_primary_core())
104 return 0;
105
106 for (i = 0; i < L2C310_COUNTERS_NUM; i++) {
107 if (l2c310_counters[i].enabled) {
108 l2c310_buffer[len++] = l2c310_counters[i].key;
109 l2c310_buffer[len++] = readl(l2c310_base +
110 l2x0_event_cntx_val[i]);
111 }
112 }
113
114 /* l2c310 counters are saturating, not wrapping in case of overflow */
115 gator_events_l2c310_reset_counters();
116
117 if (buffer)
118 *buffer = l2c310_buffer;
119
120 return len;
121}
122
123static struct gator_interface gator_events_l2c310_interface = {
124 .create_files = gator_events_l2c310_create_files,
125 .start = gator_events_l2c310_start,
126 .stop = gator_events_l2c310_stop,
127 .read = gator_events_l2c310_read,
128};
129
130#define L2C310_ADDR_PROBE (~0)
131
132MODULE_PARM_DESC(l2c310_addr, "L2C310 physical base address (0 to disable)");
133static unsigned long l2c310_addr = L2C310_ADDR_PROBE;
134module_param(l2c310_addr, ulong, 0444);
135
136static void __iomem *gator_events_l2c310_probe(void)
137{
138 phys_addr_t variants[] = {
139#if defined(CONFIG_ARCH_EXYNOS4) || defined(CONFIG_ARCH_S5PV310)
140 0x10502000,
141#endif
142#if defined(CONFIG_ARCH_OMAP4)
143 0x48242000,
144#endif
145#if defined(CONFIG_ARCH_TEGRA)
146 0x50043000,
147#endif
148#if defined(CONFIG_ARCH_U8500)
149 0xa0412000,
150#endif
151#if defined(CONFIG_ARCH_VEXPRESS)
152 0x1e00a000, // A9x4 core tile (HBI-0191)
153 0x2c0f0000, // New memory map tiles
154#endif
155 };
156 int i;
157 void __iomem *base;
158#if defined(CONFIG_OF)
159 struct device_node *node = of_find_all_nodes(NULL);
160
161 if (node) {
162 of_node_put(node);
163
164 node = of_find_compatible_node(NULL, NULL, "arm,pl310-cache");
165 base = of_iomap(node, 0);
166 of_node_put(node);
167
168 return base;
169 }
170#endif
171
172 for (i = 0; i < ARRAY_SIZE(variants); i++) {
173 base = ioremap(variants[i], SZ_4K);
174 if (base) {
175 u32 cache_id = readl(base + L2X0_CACHE_ID);
176
177 if ((cache_id & 0xff0003c0) == 0x410000c0)
178 return base;
179
180 iounmap(base);
181 }
182 }
183
184 return NULL;
185}
186
187int gator_events_l2c310_init(void)
188{
189 int i;
190
191 if (gator_cpuid() != CORTEX_A5 && gator_cpuid() != CORTEX_A9)
192 return -1;
193
194 if (l2c310_addr == L2C310_ADDR_PROBE)
195 l2c310_base = gator_events_l2c310_probe();
196 else if (l2c310_addr)
197 l2c310_base = ioremap(l2c310_addr, SZ_4K);
198
199 if (!l2c310_base)
200 return -1;
201
202 for (i = 0; i < L2C310_COUNTERS_NUM; i++) {
203 l2c310_counters[i].enabled = 0;
204 l2c310_counters[i].key = gator_events_get_key();
205 }
206
207 return gator_events_install(&gator_events_l2c310_interface);
208}
diff --git a/drivers/gator/gator_events_mali_4xx.c b/drivers/gator/gator_events_mali_4xx.c
new file mode 100644
index 00000000000..9e1c7064bd7
--- /dev/null
+++ b/drivers/gator/gator_events_mali_4xx.c
@@ -0,0 +1,669 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "gator.h"
10
11#include <linux/module.h>
12#include <linux/time.h>
13#include <linux/math64.h>
14
15#include "linux/mali_linux_trace.h"
16
17#include "gator_events_mali_common.h"
18#include "gator_events_mali_4xx.h"
19
20/*
21* There have been four different variants of the comms between gator and Mali depending on driver version:
22* # | DDK vsn range | Support | Notes
23*
24* 1 | (obsolete) | No software counter support | Obsolete patches
25* 2 | (obsolete) | Tracepoint called for each separate s/w counter value as it appears | Obsolete patches
26* 3 | r3p0-04rel0 - r3p2-01rel2 | Single tracepoint for all s/w counters in a bundle. |
27* 4 | r3p2-01rel3 - date | As above but with extensions for MP devices (Mali-450) | At least r4p0-00rel1
28*/
29
30#if !defined(GATOR_MALI_INTERFACE_STYLE)
31#define GATOR_MALI_INTERFACE_STYLE (4)
32#endif
33
34#if GATOR_MALI_INTERFACE_STYLE == 1
35#error GATOR_MALI_INTERFACE_STYLE 1 is obsolete
36#elif GATOR_MALI_INTERFACE_STYLE == 2
37#error GATOR_MALI_INTERFACE_STYLE 2 is obsolete
38#elif GATOR_MALI_INTERFACE_STYLE >= 3
39// Valid GATOR_MALI_INTERFACE_STYLE
40#else
41#error Unknown GATOR_MALI_INTERFACE_STYLE option.
42#endif
43
44#if GATOR_MALI_INTERFACE_STYLE < 4
45#include "mali/mali_mjollnir_profiling_gator_api.h"
46#else
47#include "mali/mali_utgard_profiling_gator_api.h"
48#endif
49
50/*
51 * Check that the MALI_SUPPORT define is set to one of the allowable device codes.
52 */
53#if (MALI_SUPPORT != MALI_4xx)
54#error MALI_SUPPORT set to an invalid device code: expecting MALI_4xx
55#endif
56
57static const char mali_name[] = "Mali-4xx";
58
59/* gatorfs variables for counter enable state,
60 * the event the counter should count and the
61 * 'key' (a unique id set by gatord and returned
62 * by gator.ko)
63 */
64static unsigned long counter_enabled[NUMBER_OF_EVENTS];
65static unsigned long counter_event[NUMBER_OF_EVENTS];
66static unsigned long counter_key[NUMBER_OF_EVENTS];
67
68/* The data we have recorded */
69static u32 counter_data[NUMBER_OF_EVENTS];
70/* The address to sample (or 0 if samples are sent to us) */
71static u32 *counter_address[NUMBER_OF_EVENTS];
72
73/* An array used to return the data we recorded
74 * as key,value pairs hence the *2
75 */
76static unsigned long counter_dump[NUMBER_OF_EVENTS * 2];
77static unsigned long counter_prev[NUMBER_OF_EVENTS];
78static bool prev_set[NUMBER_OF_EVENTS];
79
80/* Note whether tracepoints have been registered */
81static int trace_registered;
82
83/*
84 * These numbers define the actual numbers of each block type that exist in the system. Initially
85 * these are set to the maxima defined above; if the driver is capable of being queried (newer
86 * drivers only) then the values may be revised.
87 */
88static unsigned int n_vp_cores = MAX_NUM_VP_CORES;
89static unsigned int n_l2_cores = MAX_NUM_L2_CACHE_CORES;
90static unsigned int n_fp_cores = MAX_NUM_FP_CORES;
91
92extern mali_counter mali_activity[2];
93static const char* const mali_activity_names[] = {
94 "fragment",
95 "vertex",
96};
97
98/**
99 * Returns non-zero if the given counter ID is an activity counter.
100 */
101static inline int is_activity_counter(unsigned int event_id)
102{
103 return (event_id >= FIRST_ACTIVITY_EVENT &&
104 event_id <= LAST_ACTIVITY_EVENT);
105}
106
107/**
108 * Returns non-zero if the given counter ID is a hardware counter.
109 */
110static inline int is_hw_counter(unsigned int event_id)
111{
112 return (event_id >= FIRST_HW_COUNTER && event_id <= LAST_HW_COUNTER);
113}
114
115/*
116 * These are provided for utgard compatibility.
117 */
118typedef void _mali_profiling_get_mali_version_type(struct _mali_profiling_mali_version *values);
119typedef u32 _mali_profiling_get_l2_counters_type(_mali_profiling_l2_counter_values *values);
120
121/* Probe for continuously sampled counter */
122#if 0 //WE_DONT_CURRENTLY_USE_THIS_SO_SUPPRESS_WARNING
123GATOR_DEFINE_PROBE(mali_sample_address, TP_PROTO(unsigned int event_id, u32 *addr))
124{
125 /* Turning on too many pr_debug statements in frequently called functions
126 * can cause stability and/or performance problems
127 */
128 //pr_debug("gator: mali_sample_address %d %d\n", event_id, addr);
129 if (event_id >= ACTIVITY_VP && event_id <= COUNTER_FP3_C1) {
130 counter_address[event_id] = addr;
131 }
132}
133#endif
134
135/* Probe for hardware counter events */
136GATOR_DEFINE_PROBE(mali_hw_counter, TP_PROTO(unsigned int event_id, unsigned int value))
137{
138 /* Turning on too many pr_debug statements in frequently called functions
139 * can cause stability and/or performance problems
140 */
141 //pr_debug("gator: mali_hw_counter %d %d\n", event_id, value);
142 if (is_hw_counter(event_id)) {
143 counter_data[event_id] = value;
144 }
145}
146
147GATOR_DEFINE_PROBE(mali_sw_counters, TP_PROTO(pid_t pid, pid_t tid, void *surface_id, unsigned int *counters))
148{
149 u32 i;
150
151 /* Copy over the values for those counters which are enabled. */
152 for (i = FIRST_SW_COUNTER; i <= LAST_SW_COUNTER; i++) {
153 if (counter_enabled[i]) {
154 counter_data[i] = (u32)(counters[i - FIRST_SW_COUNTER]);
155 }
156 }
157}
158
159/**
160 * Create a single filesystem entry for a specified event.
161 * @param sb the superblock
162 * @param root Filesystem root
163 * @param name The name of the entry to create
164 * @param event The ID of the event
165 * @param create_event_item boolean indicating whether to create an 'event' filesystem entry. True to create.
166 *
167 * @return 0 if ok, non-zero if the create failed.
168 */
169static int create_fs_entry(struct super_block *sb, struct dentry *root, const char *name, int event, int create_event_item)
170{
171 struct dentry *dir;
172
173 dir = gatorfs_mkdir(sb, root, name);
174
175 if (!dir) {
176 return -1;
177 }
178
179 if (create_event_item) {
180 gatorfs_create_ulong(sb, dir, "event", &counter_event[event]);
181 }
182
183 gatorfs_create_ulong(sb, dir, "enabled", &counter_enabled[event]);
184 gatorfs_create_ro_ulong(sb, dir, "key", &counter_key[event]);
185
186 return 0;
187}
188
189#if GATOR_MALI_INTERFACE_STYLE > 3
190/*
191 * Read the version info structure if available
192 */
193static void initialise_version_info(void)
194{
195 _mali_profiling_get_mali_version_type *mali_profiling_get_mali_version_symbol;
196
197 mali_profiling_get_mali_version_symbol = symbol_get(_mali_profiling_get_mali_version);
198
199 if (mali_profiling_get_mali_version_symbol) {
200 struct _mali_profiling_mali_version version_info;
201
202 pr_debug("gator: mali online _mali_profiling_get_mali_version symbol @ %p\n",
203 mali_profiling_get_mali_version_symbol);
204
205 /*
206 * Revise the number of each different core type using information derived from the DDK.
207 */
208 mali_profiling_get_mali_version_symbol(&version_info);
209
210 n_fp_cores = version_info.num_of_fp_cores;
211 n_vp_cores = version_info.num_of_vp_cores;
212 n_l2_cores = version_info.num_of_l2_cores;
213
214 /* Release the function - we're done with it. */
215 symbol_put(_mali_profiling_get_mali_version);
216 } else {
217 printk("gator: mali online _mali_profiling_get_mali_version symbol not found\n");
218 printk("gator: check your Mali DDK version versus the GATOR_MALI_INTERFACE_STYLE setting\n");
219 }
220}
221#endif
222
223static int create_files(struct super_block *sb, struct dentry *root)
224{
225 int event;
226
227 char buf[40];
228 int core_id;
229 int counter_number;
230
231 pr_debug("gator: Initialising counters with style = %d\n", GATOR_MALI_INTERFACE_STYLE);
232
233#if GATOR_MALI_INTERFACE_STYLE > 3
234 /*
235 * Initialise first: this sets up the number of cores available (on compatible DDK versions).
236 * Ideally this would not need guarding but other parts of the code depend on the interface style being set
237 * correctly; if it is not then the system can enter an inconsistent state.
238 */
239 initialise_version_info();
240#endif
241
242 mali_activity[0].cores = n_fp_cores;
243 mali_activity[1].cores = n_vp_cores;
244 for (event = 0; event < ARRAY_SIZE(mali_activity); event++) {
245 if (gator_mali_create_file_system(mali_name, mali_activity_names[event], sb, root, &mali_activity[event], NULL) != 0) {
246 return -1;
247 }
248 }
249
250 /* Vertex processor counters */
251 for (core_id = 0; core_id < n_vp_cores; core_id++) {
252 int activity_counter_id = ACTIVITY_VP_0;
253 snprintf(buf, sizeof buf, "ARM_%s_VP_%d_active", mali_name, core_id);
254 if (create_fs_entry(sb, root, buf, activity_counter_id, 0) != 0) {
255 return -1;
256 }
257
258 for (counter_number = 0; counter_number < 2; counter_number++) {
259 int counter_id = COUNTER_VP_0_C0 + (2 * core_id) + counter_number;
260
261 snprintf(buf, sizeof buf, "ARM_%s_VP_%d_cnt%d", mali_name, core_id, counter_number);
262 if (create_fs_entry(sb, root, buf, counter_id, 1) != 0) {
263 return -1;
264 }
265 }
266 }
267
268 /* Fragment processors' counters */
269 for (core_id = 0; core_id < n_fp_cores; core_id++) {
270 int activity_counter_id = ACTIVITY_FP_0 + core_id;
271
272 snprintf(buf, sizeof buf, "ARM_%s_FP_%d_active", mali_name, core_id);
273 if (create_fs_entry(sb, root, buf, activity_counter_id, 0) != 0) {
274 return -1;
275 }
276
277 for (counter_number = 0; counter_number < 2; counter_number++) {
278 int counter_id = COUNTER_FP_0_C0 + (2 * core_id) + counter_number;
279
280 snprintf(buf, sizeof buf, "ARM_%s_FP_%d_cnt%d", mali_name, core_id, counter_number);
281 if (create_fs_entry(sb, root, buf, counter_id, 1) != 0) {
282 return -1;
283 }
284 }
285 }
286
287 /* L2 Cache counters */
288 for (core_id = 0; core_id < n_l2_cores; core_id++) {
289 for (counter_number = 0; counter_number < 2; counter_number++) {
290 int counter_id = COUNTER_L2_0_C0 + (2 * core_id) + counter_number;
291
292 snprintf(buf, sizeof buf, "ARM_%s_L2_%d_cnt%d", mali_name, core_id, counter_number);
293 if (create_fs_entry(sb, root, buf, counter_id, 1) != 0) {
294 return -1;
295 }
296 }
297 }
298
299 /* Now set up the software counter entries */
300 for (event = FIRST_SW_COUNTER; event <= LAST_SW_COUNTER; event++) {
301 snprintf(buf, sizeof(buf), "ARM_%s_SW_%d", mali_name, event - FIRST_SW_COUNTER);
302
303 if (create_fs_entry(sb, root, buf, event, 0) != 0) {
304 return -1;
305 }
306 }
307
308 /* Now set up the special counter entries */
309 snprintf(buf, sizeof(buf), "ARM_%s_Filmstrip_cnt0", mali_name);
310 if (create_fs_entry(sb, root, buf, COUNTER_FILMSTRIP, 1) != 0) {
311 return -1;
312 }
313
314#ifdef DVFS_REPORTED_BY_DDK
315 snprintf(buf, sizeof(buf), "ARM_%s_Frequency", mali_name);
316 if (create_fs_entry(sb, root, buf, COUNTER_FREQUENCY, 1) != 0) {
317 return -1;
318 }
319
320 snprintf(buf, sizeof(buf), "ARM_%s_Voltage", mali_name);
321 if (create_fs_entry(sb, root, buf, COUNTER_VOLTAGE, 1) != 0) {
322 return -1;
323 }
324#endif
325
326 return 0;
327}
328
329/*
330 * Local store for the get_counters entry point into the DDK.
331 * This is stored here since it is used very regularly.
332 */
333static mali_profiling_get_counters_type *mali_get_counters = NULL;
334static _mali_profiling_get_l2_counters_type *mali_get_l2_counters = NULL;
335
336/*
337 * Examine list of counters between two index limits and determine if any one is enabled.
338 * Returns 1 if any counter is enabled, 0 if none is.
339 */
340static int is_any_counter_enabled(unsigned int first_counter, unsigned int last_counter)
341{
342 unsigned int i;
343
344 for (i = first_counter; i <= last_counter; i++) {
345 if (counter_enabled[i]) {
346 return 1; /* At least one counter is enabled */
347 }
348 }
349
350 return 0; /* No s/w counters enabled */
351}
352
353static void init_counters(unsigned int from_counter, unsigned int to_counter)
354{
355 unsigned int counter_id;
356
357 /* If a Mali driver is present and exporting the appropriate symbol
358 * then we can request the HW counters (of which there are only 2)
359 * be configured to count the desired events
360 */
361 mali_profiling_set_event_type *mali_set_hw_event;
362
363 mali_set_hw_event = symbol_get(_mali_profiling_set_event);
364
365 if (mali_set_hw_event) {
366 pr_debug("gator: mali online _mali_profiling_set_event symbol @ %p\n", mali_set_hw_event);
367
368 for (counter_id = from_counter; counter_id <= to_counter; counter_id++) {
369 if (counter_enabled[counter_id]) {
370 mali_set_hw_event(counter_id, counter_event[counter_id]);
371 } else {
372 mali_set_hw_event(counter_id, 0xFFFFFFFF);
373 }
374 }
375
376 symbol_put(_mali_profiling_set_event);
377 } else {
378 printk("gator: mali online _mali_profiling_set_event symbol not found\n");
379 }
380}
381
382static void mali_counter_initialize(void)
383{
384 int i;
385
386 mali_profiling_control_type *mali_control;
387
388 init_counters(COUNTER_L2_0_C0, COUNTER_L2_0_C0 + (2 * n_l2_cores) - 1);
389 init_counters(COUNTER_VP_0_C0, COUNTER_VP_0_C0 + (2 * n_vp_cores) - 1);
390 init_counters(COUNTER_FP_0_C0, COUNTER_FP_0_C0 + (2 * n_fp_cores) - 1);
391
392 /* Generic control interface for Mali DDK. */
393 mali_control = symbol_get(_mali_profiling_control);
394 if (mali_control) {
395 /* The event attribute in the XML file keeps the actual frame rate. */
396 unsigned int rate = counter_event[COUNTER_FILMSTRIP] & 0xff;
397 unsigned int resize_factor = (counter_event[COUNTER_FILMSTRIP] >> 8) & 0xff;
398
399 pr_debug("gator: mali online _mali_profiling_control symbol @ %p\n", mali_control);
400
401 mali_control(SW_COUNTER_ENABLE, (is_any_counter_enabled(FIRST_SW_COUNTER, LAST_SW_COUNTER) ? 1 : 0));
402 mali_control(FBDUMP_CONTROL_ENABLE, (counter_enabled[COUNTER_FILMSTRIP] ? 1 : 0));
403 mali_control(FBDUMP_CONTROL_RATE, rate);
404 mali_control(FBDUMP_CONTROL_RESIZE_FACTOR, resize_factor);
405
406 pr_debug("gator: sent mali_control enabled=%d, rate=%d\n", (counter_enabled[COUNTER_FILMSTRIP] ? 1 : 0), rate);
407
408 symbol_put(_mali_profiling_control);
409 } else {
410 printk("gator: mali online _mali_profiling_control symbol not found\n");
411 }
412
413 mali_get_counters = symbol_get(_mali_profiling_get_counters);
414 if (mali_get_counters) {
415 pr_debug("gator: mali online _mali_profiling_get_counters symbol @ %p\n", mali_get_counters);
416
417 } else {
418 pr_debug("gator WARNING: mali _mali_profiling_get_counters symbol not defined");
419 }
420
421 mali_get_l2_counters = symbol_get(_mali_profiling_get_l2_counters);
422 if (mali_get_l2_counters) {
423 pr_debug("gator: mali online _mali_profiling_get_l2_counters symbol @ %p\n", mali_get_l2_counters);
424
425 } else {
426 pr_debug("gator WARNING: mali _mali_profiling_get_l2_counters symbol not defined");
427 }
428
429 if (!mali_get_counters && !mali_get_l2_counters) {
430 pr_debug("gator: WARNING: no L2 counters available");
431 n_l2_cores = 0;
432 }
433
434 /* Clear counters in the start */
435 for (i = 0; i < NUMBER_OF_EVENTS; i++) {
436 counter_data[i] = 0;
437 prev_set[i] = false;
438 }
439}
440
441static void mali_counter_deinitialize(void)
442{
443 mali_profiling_set_event_type *mali_set_hw_event;
444 mali_profiling_control_type *mali_control;
445
446 mali_set_hw_event = symbol_get(_mali_profiling_set_event);
447
448 if (mali_set_hw_event) {
449 int i;
450
451 pr_debug("gator: mali offline _mali_profiling_set_event symbol @ %p\n", mali_set_hw_event);
452 for (i = FIRST_HW_COUNTER; i <= LAST_HW_COUNTER; i++) {
453 mali_set_hw_event(i, 0xFFFFFFFF);
454 }
455
456 symbol_put(_mali_profiling_set_event);
457 } else {
458 printk("gator: mali offline _mali_profiling_set_event symbol not found\n");
459 }
460
461 /* Generic control interface for Mali DDK. */
462 mali_control = symbol_get(_mali_profiling_control);
463
464 if (mali_control) {
465 pr_debug("gator: mali offline _mali_profiling_control symbol @ %p\n", mali_control);
466
467 /* Reset the DDK state - disable counter collection */
468 mali_control(SW_COUNTER_ENABLE, 0);
469
470 mali_control(FBDUMP_CONTROL_ENABLE, 0);
471
472 symbol_put(_mali_profiling_control);
473 } else {
474 printk("gator: mali offline _mali_profiling_control symbol not found\n");
475 }
476
477 if (mali_get_counters) {
478 symbol_put(_mali_profiling_get_counters);
479 }
480
481 if (mali_get_l2_counters) {
482 symbol_put(_mali_profiling_get_l2_counters);
483 }
484}
485
486static int start(void)
487{
488 // register tracepoints
489 if (GATOR_REGISTER_TRACE(mali_hw_counter)) {
490 printk("gator: mali_hw_counter tracepoint failed to activate\n");
491 return -1;
492 }
493
494 /* For Mali drivers with built-in support. */
495 if (GATOR_REGISTER_TRACE(mali_sw_counters)) {
496 printk("gator: mali_sw_counters tracepoint failed to activate\n");
497 return -1;
498 }
499
500 trace_registered = 1;
501
502 mali_counter_initialize();
503 return 0;
504}
505
506static void stop(void)
507{
508 unsigned int cnt;
509
510 pr_debug("gator: mali stop\n");
511
512 if (trace_registered) {
513 GATOR_UNREGISTER_TRACE(mali_hw_counter);
514
515 /* For Mali drivers with built-in support. */
516 GATOR_UNREGISTER_TRACE(mali_sw_counters);
517
518 pr_debug("gator: mali timeline tracepoint deactivated\n");
519
520 trace_registered = 0;
521 }
522
523 for (cnt = 0; cnt < NUMBER_OF_EVENTS; cnt++) {
524 counter_enabled[cnt] = 0;
525 counter_event[cnt] = 0;
526 counter_address[cnt] = NULL;
527 }
528
529 mali_counter_deinitialize();
530}
531
532static void dump_counters(unsigned int from_counter, unsigned int to_counter, unsigned int *len)
533{
534 unsigned int counter_id;
535
536 for (counter_id = from_counter; counter_id <= to_counter; counter_id++) {
537 if (counter_enabled[counter_id]) {
538 counter_dump[(*len)++] = counter_key[counter_id];
539 counter_dump[(*len)++] = counter_data[counter_id];
540
541 counter_data[counter_id] = 0;
542 }
543 }
544}
545
546static int read(int **buffer)
547{
548 int len = 0;
549
550 if (!on_primary_core())
551 return 0;
552
553 // Read the L2 C0 and C1 here.
554 if (n_l2_cores > 0 && is_any_counter_enabled(COUNTER_L2_0_C0, COUNTER_L2_0_C0 + (2 * n_l2_cores))) {
555 unsigned int unavailable_l2_caches = 0;
556 _mali_profiling_l2_counter_values cache_values;
557 unsigned int cache_id;
558 struct _mali_profiling_core_counters *per_core;
559
560 /* Poke the driver to get the counter values - older style; only one L2 cache */
561 if (mali_get_l2_counters) {
562 unavailable_l2_caches = mali_get_l2_counters(&cache_values);
563 } else if (mali_get_counters) {
564 per_core = &cache_values.cores[0];
565 mali_get_counters(&per_core->source0, &per_core->value0, &per_core->source1, &per_core->value1);
566 } else {
567 /* This should never happen, as n_l2_caches is only set > 0 if one of the above functions is found. */
568 }
569
570 /* Fill in the two cache counter values for each cache block. */
571 for (cache_id = 0; cache_id < n_l2_cores; cache_id++) {
572 unsigned int counter_id_0 = COUNTER_L2_0_C0 + (2 * cache_id);
573 unsigned int counter_id_1 = counter_id_0 + 1;
574
575 if ((1 << cache_id) & unavailable_l2_caches) {
576 continue; /* This cache is unavailable (powered-off, possibly). */
577 }
578
579 per_core = &cache_values.cores[cache_id];
580
581 if (counter_enabled[counter_id_0] && prev_set[counter_id_0]) {
582 // Calculate and save src0's counter val0
583 counter_dump[len++] = counter_key[counter_id_0];
584 counter_dump[len++] = per_core->value0 - counter_prev[counter_id_0];
585 }
586
587 if (counter_enabled[counter_id_1] && prev_set[counter_id_1]) {
588 // Calculate and save src1's counter val1
589 counter_dump[len++] = counter_key[counter_id_1];
590 counter_dump[len++] = per_core->value1 - counter_prev[counter_id_1];
591 }
592
593 // Save the previous values for the counters.
594 counter_prev[counter_id_0] = per_core->value0;
595 prev_set[counter_id_0] = true;
596 counter_prev[counter_id_1] = per_core->value1;
597 prev_set[counter_id_1] = true;
598 }
599 }
600
601 /* Process other (non-timeline) counters. */
602 dump_counters(COUNTER_VP_0_C0, COUNTER_VP_0_C0 + (2 * n_vp_cores) - 1, &len);
603 dump_counters(COUNTER_FP_0_C0, COUNTER_FP_0_C0 + (2 * n_fp_cores) - 1, &len);
604
605 dump_counters(FIRST_SW_COUNTER, LAST_SW_COUNTER, &len);
606
607#ifdef DVFS_REPORTED_BY_DDK
608 {
609 int cnt;
610 /*
611 * Add in the voltage and frequency counters if enabled. Note that, since these are
612 * actually passed as events, the counter value should not be cleared.
613 */
614 cnt = COUNTER_FREQUENCY;
615 if (counter_enabled[cnt]) {
616 counter_dump[len++] = counter_key[cnt];
617 counter_dump[len++] = counter_data[cnt];
618 }
619
620 cnt = COUNTER_VOLTAGE;
621 if (counter_enabled[cnt]) {
622 counter_dump[len++] = counter_key[cnt];
623 counter_dump[len++] = counter_data[cnt];
624 }
625 }
626#endif
627
628 if (buffer) {
629 *buffer = (int *)counter_dump;
630 }
631
632 return len;
633}
634
635static struct gator_interface gator_events_mali_interface = {
636 .create_files = create_files,
637 .start = start,
638 .stop = stop,
639 .read = read,
640};
641
642extern void gator_events_mali_log_dvfs_event(unsigned int frequency_mhz, unsigned int voltage_mv)
643{
644#ifdef DVFS_REPORTED_BY_DDK
645 counter_data[COUNTER_FREQUENCY] = frequency_mhz;
646 counter_data[COUNTER_VOLTAGE] = voltage_mv;
647#endif
648}
649
650int gator_events_mali_init(void)
651{
652 unsigned int cnt;
653
654 pr_debug("gator: mali init\n");
655
656 gator_mali_initialise_counters(mali_activity, ARRAY_SIZE(mali_activity));
657
658 for (cnt = 0; cnt < NUMBER_OF_EVENTS; cnt++) {
659 counter_enabled[cnt] = 0;
660 counter_event[cnt] = 0;
661 counter_key[cnt] = gator_events_get_key();
662 counter_address[cnt] = NULL;
663 counter_data[cnt] = 0;
664 }
665
666 trace_registered = 0;
667
668 return gator_events_install(&gator_events_mali_interface);
669}
diff --git a/drivers/gator/gator_events_mali_4xx.h b/drivers/gator/gator_events_mali_4xx.h
new file mode 100644
index 00000000000..976ca8c4cfa
--- /dev/null
+++ b/drivers/gator/gator_events_mali_4xx.h
@@ -0,0 +1,18 @@
1/**
2 * Copyright (C) ARM Limited 2011-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10/*
11 * Header contains common definitions for the Mali-4xx processors.
12 */
13#if !defined(GATOR_EVENTS_MALI_4xx_H)
14#define GATOR_EVENTS_MALI_4xx_H
15
16extern void gator_events_mali_log_dvfs_event(unsigned int d0, unsigned int d1);
17
18#endif /* GATOR_EVENTS_MALI_4xx_H */
diff --git a/drivers/gator/gator_events_mali_common.c b/drivers/gator/gator_events_mali_common.c
new file mode 100644
index 00000000000..4f2cce4ce67
--- /dev/null
+++ b/drivers/gator/gator_events_mali_common.c
@@ -0,0 +1,69 @@
1/**
2 * Copyright (C) ARM Limited 2012-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9#include "gator_events_mali_common.h"
10
11extern int gator_mali_create_file_system(const char *mali_name, const char *event_name, struct super_block *sb, struct dentry *root, mali_counter *counter, unsigned long *event)
12{
13 int err;
14 char buf[255];
15 struct dentry *dir;
16
17 /* If the counter name is empty ignore it */
18 if (strlen(event_name) != 0) {
19 /* Set up the filesystem entry for this event. */
20 snprintf(buf, sizeof(buf), "ARM_%s_%s", mali_name, event_name);
21
22 dir = gatorfs_mkdir(sb, root, buf);
23
24 if (dir == NULL) {
25 pr_debug("gator: %s: error creating file system for: %s (%s)", mali_name, event_name, buf);
26 return -1;
27 }
28
29 err = gatorfs_create_ulong(sb, dir, "enabled", &counter->enabled);
30 if (err != 0) {
31 pr_debug("gator: %s: error calling gatorfs_create_ulong for: %s (%s)", mali_name, event_name, buf);
32 return -1;
33 }
34 err = gatorfs_create_ro_ulong(sb, dir, "key", &counter->key);
35 if (err != 0) {
36 pr_debug("gator: %s: error calling gatorfs_create_ro_ulong for: %s (%s)", mali_name, event_name, buf);
37 return -1;
38 }
39 if (counter->cores != -1) {
40 err = gatorfs_create_ro_ulong(sb, dir, "cores", &counter->cores);
41 if (err != 0) {
42 pr_debug("gator: %s: error calling gatorfs_create_ro_ulong for: %s (%s)", mali_name, event_name, buf);
43 return -1;
44 }
45 }
46 if (event != NULL) {
47 err = gatorfs_create_ulong(sb, dir, "event", event);
48 if (err != 0) {
49 pr_debug("gator: %s: error calling gatorfs_create_ro_ulong for: %s (%s)", mali_name, event_name, buf);
50 return -1;
51 }
52 }
53 }
54
55 return 0;
56}
57
58extern void gator_mali_initialise_counters(mali_counter counters[], unsigned int n_counters)
59{
60 unsigned int cnt;
61
62 for (cnt = 0; cnt < n_counters; cnt++) {
63 mali_counter *counter = &counters[cnt];
64
65 counter->key = gator_events_get_key();
66 counter->enabled = 0;
67 counter->cores = -1;
68 }
69}
diff --git a/drivers/gator/gator_events_mali_common.h b/drivers/gator/gator_events_mali_common.h
new file mode 100644
index 00000000000..91d871bc915
--- /dev/null
+++ b/drivers/gator/gator_events_mali_common.h
@@ -0,0 +1,78 @@
1/**
2 * Copyright (C) ARM Limited 2012-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10#if !defined(GATOR_EVENTS_MALI_COMMON_H)
11#define GATOR_EVENTS_MALI_COMMON_H
12
13#include "gator.h"
14
15#include <linux/module.h>
16#include <linux/time.h>
17#include <linux/math64.h>
18#include <linux/slab.h>
19#include <asm/io.h>
20
21/* Ensure that MALI_SUPPORT has been defined to something. */
22#ifndef MALI_SUPPORT
23#error MALI_SUPPORT not defined!
24#endif
25
26/* Values for the supported activity event types */
27#define ACTIVITY_START (1)
28#define ACTIVITY_STOP (2)
29
30/*
31 * Runtime state information for a counter.
32 */
33typedef struct {
34 // 'key' (a unique id set by gatord and returned by gator.ko)
35 unsigned long key;
36 // counter enable state
37 unsigned long enabled;
38 // for activity counters, the number of cores, otherwise -1
39 unsigned long cores;
40} mali_counter;
41
42/*
43 * Mali-4xx
44 */
45typedef int mali_profiling_set_event_type(unsigned int, int);
46typedef void mali_profiling_control_type(unsigned int, unsigned int);
47typedef void mali_profiling_get_counters_type(unsigned int *, unsigned int *, unsigned int *, unsigned int *);
48
49/*
50 * Driver entry points for functions called directly by gator.
51 */
52extern int _mali_profiling_set_event(unsigned int, int);
53extern void _mali_profiling_control(unsigned int, unsigned int);
54extern void _mali_profiling_get_counters(unsigned int *, unsigned int *, unsigned int *, unsigned int *);
55
56/**
57 * Creates a filesystem entry under /dev/gator relating to the specified event name and key, and
58 * associate the key/enable values with this entry point.
59 *
60 * @param event_name The name of the event.
61 * @param sb Linux super block
62 * @param root Directory under which the entry will be created.
63 * @param counter_key Ptr to location which will be associated with the counter key.
64 * @param counter_enabled Ptr to location which will be associated with the counter enable state.
65 *
66 * @return 0 if entry point was created, non-zero if not.
67 */
68extern int gator_mali_create_file_system(const char *mali_name, const char *event_name, struct super_block *sb, struct dentry *root, mali_counter *counter, unsigned long *event);
69
70/**
71 * Initializes the counter array.
72 *
73 * @param keys The array of counters
74 * @param n_counters The number of entries in each of the arrays.
75 */
76extern void gator_mali_initialise_counters(mali_counter counters[], unsigned int n_counters);
77
78#endif /* GATOR_EVENTS_MALI_COMMON_H */
diff --git a/drivers/gator/gator_events_mali_t6xx.c b/drivers/gator/gator_events_mali_t6xx.c
new file mode 100644
index 00000000000..e56ba84aefb
--- /dev/null
+++ b/drivers/gator/gator_events_mali_t6xx.c
@@ -0,0 +1,567 @@
1/**
2 * Copyright (C) ARM Limited 2011-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10#include "gator.h"
11
12#include <linux/module.h>
13#include <linux/time.h>
14#include <linux/math64.h>
15#include <linux/slab.h>
16#include <asm/io.h>
17
18#ifdef MALI_DIR_MIDGARD
19/* New DDK Directory structure with kernel/drivers/gpu/arm/midgard*/
20#include "mali_linux_trace.h"
21#else
22/* Old DDK Directory structure with kernel/drivers/gpu/arm/t6xx*/
23#include "linux/mali_linux_trace.h"
24#endif
25
26#include "gator_events_mali_common.h"
27
28/*
29 * Check that the MALI_SUPPORT define is set to one of the allowable device codes.
30 */
31#if (MALI_SUPPORT != MALI_T6xx)
32#error MALI_SUPPORT set to an invalid device code: expecting MALI_T6xx
33#endif
34
35static const char mali_name[] = "Mali-T6xx";
36
37/* Counters for Mali-T6xx:
38 *
39 * - Timeline events
40 * They are tracepoints, but instead of reporting a number they report a START/STOP event.
41 * They are reported in Streamline as number of microseconds while that particular counter was active.
42 *
43 * - SW counters
44 * They are tracepoints reporting a particular number.
45 * They are accumulated in sw_counter_data array until they are passed to Streamline, then they are zeroed.
46 *
47 * - Accumulators
48 * They are the same as software counters but their value is not zeroed.
49 */
50
51/* Timeline (start/stop) activity */
52static const char *timeline_event_names[] = {
53 "PM_SHADER_0",
54 "PM_SHADER_1",
55 "PM_SHADER_2",
56 "PM_SHADER_3",
57 "PM_SHADER_4",
58 "PM_SHADER_5",
59 "PM_SHADER_6",
60 "PM_SHADER_7",
61 "PM_TILER_0",
62 "PM_L2_0",
63 "PM_L2_1",
64 "MMU_AS_0",
65 "MMU_AS_1",
66 "MMU_AS_2",
67 "MMU_AS_3"
68};
69
70enum {
71 PM_SHADER_0 = 0,
72 PM_SHADER_1,
73 PM_SHADER_2,
74 PM_SHADER_3,
75 PM_SHADER_4,
76 PM_SHADER_5,
77 PM_SHADER_6,
78 PM_SHADER_7,
79 PM_TILER_0,
80 PM_L2_0,
81 PM_L2_1,
82 MMU_AS_0,
83 MMU_AS_1,
84 MMU_AS_2,
85 MMU_AS_3
86};
87/* The number of shader blocks in the enum above */
88#define NUM_PM_SHADER (8)
89
90/* Software Counters */
91static const char *software_counter_names[] = {
92 "MMU_PAGE_FAULT_0",
93 "MMU_PAGE_FAULT_1",
94 "MMU_PAGE_FAULT_2",
95 "MMU_PAGE_FAULT_3"
96};
97
98enum {
99 MMU_PAGE_FAULT_0 = 0,
100 MMU_PAGE_FAULT_1,
101 MMU_PAGE_FAULT_2,
102 MMU_PAGE_FAULT_3
103};
104
105/* Software Counters */
106static const char *accumulators_names[] = {
107 "TOTAL_ALLOC_PAGES"
108};
109
110enum {
111 TOTAL_ALLOC_PAGES = 0
112};
113
114#define FIRST_TIMELINE_EVENT (0)
115#define NUMBER_OF_TIMELINE_EVENTS (sizeof(timeline_event_names) / sizeof(timeline_event_names[0]))
116#define FIRST_SOFTWARE_COUNTER (FIRST_TIMELINE_EVENT + NUMBER_OF_TIMELINE_EVENTS)
117#define NUMBER_OF_SOFTWARE_COUNTERS (sizeof(software_counter_names) / sizeof(software_counter_names[0]))
118#define FIRST_ACCUMULATOR (FIRST_SOFTWARE_COUNTER + NUMBER_OF_SOFTWARE_COUNTERS)
119#define NUMBER_OF_ACCUMULATORS (sizeof(accumulators_names) / sizeof(accumulators_names[0]))
120#define FILMSTRIP (NUMBER_OF_TIMELINE_EVENTS + NUMBER_OF_SOFTWARE_COUNTERS + NUMBER_OF_ACCUMULATORS)
121#define NUMBER_OF_EVENTS (NUMBER_OF_TIMELINE_EVENTS + NUMBER_OF_SOFTWARE_COUNTERS + NUMBER_OF_ACCUMULATORS + 1)
122
123/*
124 * gatorfs variables for counter enable state
125 */
126static mali_counter counters[NUMBER_OF_EVENTS];
127static unsigned long filmstrip_event;
128
129/* An array used to return the data we recorded
130 * as key,value pairs hence the *2
131 */
132static unsigned long counter_dump[NUMBER_OF_EVENTS * 2];
133
134/*
135 * Array holding counter start times (in ns) for each counter. A zero here
136 * indicates that the activity monitored by this counter is not running.
137 */
138static struct timespec timeline_event_starttime[NUMBER_OF_TIMELINE_EVENTS];
139
140/* The data we have recorded */
141static unsigned int timeline_data[NUMBER_OF_TIMELINE_EVENTS];
142static unsigned int sw_counter_data[NUMBER_OF_SOFTWARE_COUNTERS];
143static unsigned int accumulators_data[NUMBER_OF_ACCUMULATORS];
144
145/* Hold the previous timestamp, used to calculate the sample interval. */
146static struct timespec prev_timestamp;
147
148/**
149 * Returns the timespan (in microseconds) between the two specified timestamps.
150 *
151 * @param start Ptr to the start timestamp
152 * @param end Ptr to the end timestamp
153 *
154 * @return Number of microseconds between the two timestamps (can be negative if start follows end).
155 */
156static inline long get_duration_us(const struct timespec *start, const struct timespec *end)
157{
158 long event_duration_us = (end->tv_nsec - start->tv_nsec) / 1000;
159 event_duration_us += (end->tv_sec - start->tv_sec) * 1000000;
160
161 return event_duration_us;
162}
163
164static void record_timeline_event(unsigned int timeline_index, unsigned int type)
165{
166 struct timespec event_timestamp;
167 struct timespec *event_start = &timeline_event_starttime[timeline_index];
168
169 switch (type) {
170 case ACTIVITY_START:
171 /* Get the event time... */
172 getnstimeofday(&event_timestamp);
173
174 /* Remember the start time if the activity is not already started */
175 if (event_start->tv_sec == 0) {
176 *event_start = event_timestamp; /* Structure copy */
177 }
178 break;
179
180 case ACTIVITY_STOP:
181 /* if the counter was started... */
182 if (event_start->tv_sec != 0) {
183 /* Get the event time... */
184 getnstimeofday(&event_timestamp);
185
186 /* Accumulate the duration in us */
187 timeline_data[timeline_index] += get_duration_us(event_start, &event_timestamp);
188
189 /* Reset the start time to indicate the activity is stopped. */
190 event_start->tv_sec = 0;
191 }
192 break;
193
194 default:
195 /* Other activity events are ignored. */
196 break;
197 }
198}
199
200/*
201 * Documentation about the following tracepoints is in mali_linux_trace.h
202 */
203
204GATOR_DEFINE_PROBE(mali_pm_status, TP_PROTO(unsigned int event_id, unsigned long long value))
205{
206#define SHADER_PRESENT_LO 0x100 /* (RO) Shader core present bitmap, low word */
207#define TILER_PRESENT_LO 0x110 /* (RO) Tiler core present bitmap, low word */
208#define L2_PRESENT_LO 0x120 /* (RO) Level 2 cache present bitmap, low word */
209#define BIT_AT(value, pos) ((value >> pos) & 1)
210
211 static unsigned long long previous_shader_bitmask = 0;
212 static unsigned long long previous_tiler_bitmask = 0;
213 static unsigned long long previous_l2_bitmask = 0;
214
215 switch (event_id) {
216 case SHADER_PRESENT_LO:
217 {
218 unsigned long long changed_bitmask = previous_shader_bitmask ^ value;
219 int pos;
220
221 for (pos = 0; pos < NUM_PM_SHADER; ++pos) {
222 if (BIT_AT(changed_bitmask, pos)) {
223 record_timeline_event(PM_SHADER_0 + pos, BIT_AT(value, pos) ? ACTIVITY_START : ACTIVITY_STOP);
224 }
225 }
226
227 previous_shader_bitmask = value;
228 break;
229 }
230
231 case TILER_PRESENT_LO:
232 {
233 unsigned long long changed = previous_tiler_bitmask ^ value;
234
235 if (BIT_AT(changed, 0)) {
236 record_timeline_event(PM_TILER_0, BIT_AT(value, 0) ? ACTIVITY_START : ACTIVITY_STOP);
237 }
238
239 previous_tiler_bitmask = value;
240 break;
241 }
242
243 case L2_PRESENT_LO:
244 {
245 unsigned long long changed = previous_l2_bitmask ^ value;
246
247 if (BIT_AT(changed, 0)) {
248 record_timeline_event(PM_L2_0, BIT_AT(value, 0) ? ACTIVITY_START : ACTIVITY_STOP);
249 }
250 if (BIT_AT(changed, 4)) {
251 record_timeline_event(PM_L2_1, BIT_AT(value, 4) ? ACTIVITY_START : ACTIVITY_STOP);
252 }
253
254 previous_l2_bitmask = value;
255 break;
256 }
257
258 default:
259 /* No other blocks are supported at present */
260 break;
261 }
262
263#undef SHADER_PRESENT_LO
264#undef TILER_PRESENT_LO
265#undef L2_PRESENT_LO
266#undef BIT_AT
267}
268
269GATOR_DEFINE_PROBE(mali_page_fault_insert_pages, TP_PROTO(int event_id, unsigned long value))
270{
271 /* We add to the previous since we may receive many tracepoints in one sample period */
272 sw_counter_data[MMU_PAGE_FAULT_0 + event_id] += value;
273}
274
275GATOR_DEFINE_PROBE(mali_mmu_as_in_use, TP_PROTO(int event_id))
276{
277 record_timeline_event(MMU_AS_0 + event_id, ACTIVITY_START);
278}
279
280GATOR_DEFINE_PROBE(mali_mmu_as_released, TP_PROTO(int event_id))
281{
282 record_timeline_event(MMU_AS_0 + event_id, ACTIVITY_STOP);
283}
284
285GATOR_DEFINE_PROBE(mali_total_alloc_pages_change, TP_PROTO(long long int event_id))
286{
287 accumulators_data[TOTAL_ALLOC_PAGES] = event_id;
288}
289
290static int create_files(struct super_block *sb, struct dentry *root)
291{
292 int event;
293 /*
294 * Create the filesystem for all events
295 */
296 int counter_index = 0;
297 mali_profiling_control_type *mali_control;
298
299 for (event = FIRST_TIMELINE_EVENT; event < FIRST_TIMELINE_EVENT + NUMBER_OF_TIMELINE_EVENTS; event++) {
300 if (gator_mali_create_file_system(mali_name, timeline_event_names[counter_index], sb, root, &counters[event], NULL) != 0) {
301 return -1;
302 }
303 counter_index++;
304 }
305 counter_index = 0;
306 for (event = FIRST_SOFTWARE_COUNTER; event < FIRST_SOFTWARE_COUNTER + NUMBER_OF_SOFTWARE_COUNTERS; event++) {
307 if (gator_mali_create_file_system(mali_name, software_counter_names[counter_index], sb, root, &counters[event], NULL) != 0) {
308 return -1;
309 }
310 counter_index++;
311 }
312 counter_index = 0;
313 for (event = FIRST_ACCUMULATOR; event < FIRST_ACCUMULATOR + NUMBER_OF_ACCUMULATORS; event++) {
314 if (gator_mali_create_file_system(mali_name, accumulators_names[counter_index], sb, root, &counters[event], NULL) != 0) {
315 return -1;
316 }
317 counter_index++;
318 }
319
320 mali_control = symbol_get(_mali_profiling_control);
321 if (mali_control) {
322 if (gator_mali_create_file_system(mali_name, "Filmstrip_cnt0", sb, root, &counters[FILMSTRIP], &filmstrip_event) != 0) {
323 return -1;
324 }
325 symbol_put(_mali_profiling_control);
326 }
327
328 return 0;
329}
330
331static int register_tracepoints(void)
332{
333 if (GATOR_REGISTER_TRACE(mali_pm_status)) {
334 pr_debug("gator: Mali-T6xx: mali_pm_status tracepoint failed to activate\n");
335 return 0;
336 }
337
338 if (GATOR_REGISTER_TRACE(mali_page_fault_insert_pages)) {
339 pr_debug("gator: Mali-T6xx: mali_page_fault_insert_pages tracepoint failed to activate\n");
340 return 0;
341 }
342
343 if (GATOR_REGISTER_TRACE(mali_mmu_as_in_use)) {
344 pr_debug("gator: Mali-T6xx: mali_mmu_as_in_use tracepoint failed to activate\n");
345 return 0;
346 }
347
348 if (GATOR_REGISTER_TRACE(mali_mmu_as_released)) {
349 pr_debug("gator: Mali-T6xx: mali_mmu_as_released tracepoint failed to activate\n");
350 return 0;
351 }
352
353 if (GATOR_REGISTER_TRACE(mali_total_alloc_pages_change)) {
354 pr_debug("gator: Mali-T6xx: mali_total_alloc_pages_change tracepoint failed to activate\n");
355 return 0;
356 }
357
358 pr_debug("gator: Mali-T6xx: start\n");
359 pr_debug("gator: Mali-T6xx: mali_pm_status probe is at %p\n", &probe_mali_pm_status);
360 pr_debug("gator: Mali-T6xx: mali_page_fault_insert_pages probe is at %p\n", &probe_mali_page_fault_insert_pages);
361 pr_debug("gator: Mali-T6xx: mali_mmu_as_in_use probe is at %p\n", &probe_mali_mmu_as_in_use);
362 pr_debug("gator: Mali-T6xx: mali_mmu_as_released probe is at %p\n", &probe_mali_mmu_as_released);
363 pr_debug("gator: Mali-T6xx: mali_total_alloc_pages_change probe is at %p\n", &probe_mali_total_alloc_pages_change);
364
365 return 1;
366}
367
368static int start(void)
369{
370 unsigned int cnt;
371 mali_profiling_control_type *mali_control;
372
373 /* Clean all data for the next capture */
374 for (cnt = 0; cnt < NUMBER_OF_TIMELINE_EVENTS; cnt++) {
375 timeline_event_starttime[cnt].tv_sec = timeline_event_starttime[cnt].tv_nsec = 0;
376 timeline_data[cnt] = 0;
377 }
378
379 for (cnt = 0; cnt < NUMBER_OF_SOFTWARE_COUNTERS; cnt++) {
380 sw_counter_data[cnt] = 0;
381 }
382
383 for (cnt = 0; cnt < NUMBER_OF_ACCUMULATORS; cnt++) {
384 accumulators_data[cnt] = 0;
385 }
386
387 /* Register tracepoints */
388 if (register_tracepoints() == 0) {
389 return -1;
390 }
391
392 /* Generic control interface for Mali DDK. */
393 mali_control = symbol_get(_mali_profiling_control);
394 if (mali_control) {
395 /* The event attribute in the XML file keeps the actual frame rate. */
396 unsigned int enabled = counters[FILMSTRIP].enabled ? 1 : 0;
397 unsigned int rate = filmstrip_event & 0xff;
398 unsigned int resize_factor = (filmstrip_event >> 8) & 0xff;
399
400 pr_debug("gator: mali online _mali_profiling_control symbol @ %p\n", mali_control);
401
402#define FBDUMP_CONTROL_ENABLE (1)
403#define FBDUMP_CONTROL_RATE (2)
404#define FBDUMP_CONTROL_RESIZE_FACTOR (4)
405 mali_control(FBDUMP_CONTROL_ENABLE, enabled);
406 mali_control(FBDUMP_CONTROL_RATE, rate);
407 mali_control(FBDUMP_CONTROL_RESIZE_FACTOR, resize_factor);
408
409 pr_debug("gator: sent mali_control enabled=%d, rate=%d, resize_factor=%d\n", enabled, rate, resize_factor);
410
411 symbol_put(_mali_profiling_control);
412 } else {
413 printk("gator: mali online _mali_profiling_control symbol not found\n");
414 }
415
416 /*
417 * Set the first timestamp for calculating the sample interval. The first interval could be quite long,
418 * since it will be the time between 'start' and the first 'read'.
419 * This means that timeline values will be divided by a big number for the first sample.
420 */
421 getnstimeofday(&prev_timestamp);
422
423 return 0;
424}
425
426static void stop(void)
427{
428 mali_profiling_control_type *mali_control;
429
430 pr_debug("gator: Mali-T6xx: stop\n");
431
432 /*
433 * It is safe to unregister traces even if they were not successfully
434 * registered, so no need to check.
435 */
436 GATOR_UNREGISTER_TRACE(mali_pm_status);
437 pr_debug("gator: Mali-T6xx: mali_pm_status tracepoint deactivated\n");
438
439 GATOR_UNREGISTER_TRACE(mali_page_fault_insert_pages);
440 pr_debug("gator: Mali-T6xx: mali_page_fault_insert_pages tracepoint deactivated\n");
441
442 GATOR_UNREGISTER_TRACE(mali_mmu_as_in_use);
443 pr_debug("gator: Mali-T6xx: mali_mmu_as_in_use tracepoint deactivated\n");
444
445 GATOR_UNREGISTER_TRACE(mali_mmu_as_released);
446 pr_debug("gator: Mali-T6xx: mali_mmu_as_released tracepoint deactivated\n");
447
448 GATOR_UNREGISTER_TRACE(mali_total_alloc_pages_change);
449 pr_debug("gator: Mali-T6xx: mali_total_alloc_pages_change tracepoint deactivated\n");
450
451 /* Generic control interface for Mali DDK. */
452 mali_control = symbol_get(_mali_profiling_control);
453 if (mali_control) {
454 pr_debug("gator: mali offline _mali_profiling_control symbol @ %p\n", mali_control);
455
456 mali_control(FBDUMP_CONTROL_ENABLE, 0);
457
458 symbol_put(_mali_profiling_control);
459 } else {
460 printk("gator: mali offline _mali_profiling_control symbol not found\n");
461 }
462}
463
464static int read(int **buffer)
465{
466 int cnt;
467 int len = 0;
468 long sample_interval_us = 0;
469 struct timespec read_timestamp;
470
471 if (!on_primary_core()) {
472 return 0;
473 }
474
475 /* Get the start of this sample period. */
476 getnstimeofday(&read_timestamp);
477
478 /*
479 * Calculate the sample interval if the previous sample time is valid.
480 * We use tv_sec since it will not be 0.
481 */
482 if (prev_timestamp.tv_sec != 0) {
483 sample_interval_us = get_duration_us(&prev_timestamp, &read_timestamp);
484 }
485
486 /* Structure copy. Update the previous timestamp. */
487 prev_timestamp = read_timestamp;
488
489 /*
490 * Report the timeline counters (ACTIVITY_START/STOP)
491 */
492 for (cnt = FIRST_TIMELINE_EVENT; cnt < (FIRST_TIMELINE_EVENT + NUMBER_OF_TIMELINE_EVENTS); cnt++) {
493 mali_counter *counter = &counters[cnt];
494 if (counter->enabled) {
495 const int index = cnt - FIRST_TIMELINE_EVENT;
496 unsigned int value;
497
498 /* If the activity is still running, reset its start time to the start of this sample period
499 * to correct the count. Add the time up to the end of the sample onto the count. */
500 if (timeline_event_starttime[index].tv_sec != 0) {
501 const long event_duration = get_duration_us(&timeline_event_starttime[index], &read_timestamp);
502 timeline_data[index] += event_duration;
503 timeline_event_starttime[index] = read_timestamp; /* Activity is still running. */
504 }
505
506 if (sample_interval_us != 0) {
507 /* Convert the counter to a percent-of-sample value */
508 value = (timeline_data[index] * 100) / sample_interval_us;
509 } else {
510 pr_debug("gator: Mali-T6xx: setting value to zero\n");
511 value = 0;
512 }
513
514 /* Clear the counter value ready for the next sample. */
515 timeline_data[index] = 0;
516
517 counter_dump[len++] = counter->key;
518 counter_dump[len++] = value;
519 }
520 }
521
522 /* Report the software counters */
523 for (cnt = FIRST_SOFTWARE_COUNTER; cnt < (FIRST_SOFTWARE_COUNTER + NUMBER_OF_SOFTWARE_COUNTERS); cnt++) {
524 const mali_counter *counter = &counters[cnt];
525 if (counter->enabled) {
526 const int index = cnt - FIRST_SOFTWARE_COUNTER;
527 counter_dump[len++] = counter->key;
528 counter_dump[len++] = sw_counter_data[index];
529 /* Set the value to zero for the next time */
530 sw_counter_data[index] = 0;
531 }
532 }
533
534 /* Report the accumulators */
535 for (cnt = FIRST_ACCUMULATOR; cnt < (FIRST_ACCUMULATOR + NUMBER_OF_ACCUMULATORS); cnt++) {
536 const mali_counter *counter = &counters[cnt];
537 if (counter->enabled) {
538 const int index = cnt - FIRST_ACCUMULATOR;
539 counter_dump[len++] = counter->key;
540 counter_dump[len++] = accumulators_data[index];
541 /* Do not zero the accumulator */
542 }
543 }
544
545 /* Update the buffer */
546 if (buffer) {
547 *buffer = (int *)counter_dump;
548 }
549
550 return len;
551}
552
553static struct gator_interface gator_events_mali_t6xx_interface = {
554 .create_files = create_files,
555 .start = start,
556 .stop = stop,
557 .read = read
558};
559
560extern int gator_events_mali_t6xx_init(void)
561{
562 pr_debug("gator: Mali-T6xx: sw_counters init\n");
563
564 gator_mali_initialise_counters(counters, NUMBER_OF_EVENTS);
565
566 return gator_events_install(&gator_events_mali_t6xx_interface);
567}
diff --git a/drivers/gator/gator_events_mali_t6xx_hw.c b/drivers/gator/gator_events_mali_t6xx_hw.c
new file mode 100644
index 00000000000..3a072bb6ac0
--- /dev/null
+++ b/drivers/gator/gator_events_mali_t6xx_hw.c
@@ -0,0 +1,913 @@
1/**
2 * Copyright (C) ARM Limited 2012-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10#include "gator.h"
11
12#include <linux/module.h>
13#include <linux/time.h>
14#include <linux/math64.h>
15#include <linux/slab.h>
16#include <asm/io.h>
17
18/* Mali T6xx DDK includes */
19#if defined(MALI_SIMPLE_API)
20/* Header with wrapper functions to kbase structures and functions */
21#include "mali/mali_dd_gator_api.h"
22#elif defined(MALI_DIR_MIDGARD)
23/* New DDK Directory structure with kernel/drivers/gpu/arm/midgard*/
24#include "mali_linux_trace.h"
25#include "mali_kbase.h"
26#include "mali_kbase_mem_linux.h"
27#else
28/* Old DDK Directory structure with kernel/drivers/gpu/arm/t6xx*/
29#include "linux/mali_linux_trace.h"
30#include "kbase/src/common/mali_kbase.h"
31#include "kbase/src/linux/mali_kbase_mem_linux.h"
32#endif
33
34/* If API version is not specified then assume API version 1. */
35#ifndef MALI_DDK_GATOR_API_VERSION
36#define MALI_DDK_GATOR_API_VERSION 1
37#endif
38
39#if (MALI_DDK_GATOR_API_VERSION != 1) && (MALI_DDK_GATOR_API_VERSION != 2) && (MALI_DDK_GATOR_API_VERSION != 3)
40#error MALI_DDK_GATOR_API_VERSION is invalid (must be 1 for r1/r2 DDK, or 2 for r3 DDK, or 3 for r? DDK).
41#endif
42
43#include "gator_events_mali_common.h"
44
45/*
46 * Mali-T6xx
47 */
48#if MALI_DDK_GATOR_API_VERSION == 3
49typedef uint32_t kbase_dd_instr_hwcnt_dump_irq_type(struct mali_dd_hwcnt_handles *);
50typedef uint32_t kbase_dd_instr_hwcnt_dump_complete_type(struct mali_dd_hwcnt_handles *, uint32_t *);
51typedef struct mali_dd_hwcnt_handles* mali_dd_hwcnt_init_type(struct mali_dd_hwcnt_info *);
52typedef void mali_dd_hwcnt_clear_type(struct mali_dd_hwcnt_info *, struct mali_dd_hwcnt_handles *);
53
54static kbase_dd_instr_hwcnt_dump_irq_type *kbase_dd_instr_hwcnt_dump_irq_symbol;
55static kbase_dd_instr_hwcnt_dump_complete_type *kbase_dd_instr_hwcnt_dump_complete_symbol;
56static mali_dd_hwcnt_init_type *mali_dd_hwcnt_init_symbol;
57static mali_dd_hwcnt_clear_type *mali_dd_hwcnt_clear_symbol;
58
59#else
60typedef struct kbase_device *kbase_find_device_type(int);
61typedef struct kbase_context *kbase_create_context_type(struct kbase_device *);
62typedef void kbase_destroy_context_type(struct kbase_context *);
63
64#if MALI_DDK_GATOR_API_VERSION == 1
65typedef void *kbase_va_alloc_type(struct kbase_context *, u32);
66typedef void kbase_va_free_type(struct kbase_context *, void *);
67#elif MALI_DDK_GATOR_API_VERSION == 2
68typedef void *kbase_va_alloc_type(struct kbase_context *, u32, kbase_hwc_dma_mapping * handle);
69typedef void kbase_va_free_type(struct kbase_context *, kbase_hwc_dma_mapping * handle);
70#endif
71
72typedef mali_error kbase_instr_hwcnt_enable_type(struct kbase_context *, struct kbase_uk_hwcnt_setup *);
73typedef mali_error kbase_instr_hwcnt_disable_type(struct kbase_context *);
74typedef mali_error kbase_instr_hwcnt_clear_type(struct kbase_context *);
75typedef mali_error kbase_instr_hwcnt_dump_irq_type(struct kbase_context *);
76typedef mali_bool kbase_instr_hwcnt_dump_complete_type(struct kbase_context *, mali_bool *);
77
78static kbase_find_device_type *kbase_find_device_symbol;
79static kbase_create_context_type *kbase_create_context_symbol;
80static kbase_va_alloc_type *kbase_va_alloc_symbol;
81static kbase_instr_hwcnt_enable_type *kbase_instr_hwcnt_enable_symbol;
82static kbase_instr_hwcnt_clear_type *kbase_instr_hwcnt_clear_symbol;
83static kbase_instr_hwcnt_dump_irq_type *kbase_instr_hwcnt_dump_irq_symbol;
84static kbase_instr_hwcnt_dump_complete_type *kbase_instr_hwcnt_dump_complete_symbol;
85static kbase_instr_hwcnt_disable_type *kbase_instr_hwcnt_disable_symbol;
86static kbase_va_free_type *kbase_va_free_symbol;
87static kbase_destroy_context_type *kbase_destroy_context_symbol;
88#endif
89
90static long shader_present_low = 0;
91
92/** The interval between reads, in ns.
93 *
94 * Earlier we introduced
95 * a 'hold off for 1ms after last read' to resolve MIDBASE-2178 and MALINE-724.
96 * However, the 1ms hold off is too long if no context switches occur as there is a race
97 * between this value and the tick of the read clock in gator which is also 1ms. If we 'miss' the
98 * current read, the counter values are effectively 'spread' over 2ms and the values seen are half
99 * what they should be (since Streamline averages over sample time). In the presence of context switches
100 * this spread can vary and markedly affect the counters. Currently there is no 'proper' solution to
101 * this, but empirically we have found that reducing the minimum read interval to 950us causes the
102 * counts to be much more stable.
103 */
104static const int READ_INTERVAL_NSEC = 950000;
105
106#if GATOR_TEST
107#include "gator_events_mali_t6xx_hw_test.c"
108#endif
109
110/* Blocks for HW counters */
111enum {
112 JM_BLOCK = 0,
113 TILER_BLOCK,
114 SHADER_BLOCK,
115 MMU_BLOCK
116};
117
118static const char mali_name[] = "Mali-T6xx";
119
120/* Counters for Mali-T6xx:
121 *
122 * - HW counters, 4 blocks
123 * For HW counters we need strings to create /dev/gator/events files.
124 * Enums are not needed because the position of the HW name in the array is the same
125 * of the corresponding value in the received block of memory.
126 * HW counters are requested by calculating a bitmask, passed then to the driver.
127 * Every millisecond a HW counters dump is requested, and if the previous has been completed they are read.
128 */
129
130/* Hardware Counters */
131static const char *const hardware_counter_names[] = {
132 /* Job Manager */
133 "",
134 "",
135 "",
136 "",
137 "MESSAGES_SENT",
138 "MESSAGES_RECEIVED",
139 "GPU_ACTIVE", /* 6 */
140 "IRQ_ACTIVE",
141 "JS0_JOBS",
142 "JS0_TASKS",
143 "JS0_ACTIVE",
144 "",
145 "JS0_WAIT_READ",
146 "JS0_WAIT_ISSUE",
147 "JS0_WAIT_DEPEND",
148 "JS0_WAIT_FINISH",
149 "JS1_JOBS",
150 "JS1_TASKS",
151 "JS1_ACTIVE",
152 "",
153 "JS1_WAIT_READ",
154 "JS1_WAIT_ISSUE",
155 "JS1_WAIT_DEPEND",
156 "JS1_WAIT_FINISH",
157 "JS2_JOBS",
158 "JS2_TASKS",
159 "JS2_ACTIVE",
160 "",
161 "JS2_WAIT_READ",
162 "JS2_WAIT_ISSUE",
163 "JS2_WAIT_DEPEND",
164 "JS2_WAIT_FINISH",
165 "JS3_JOBS",
166 "JS3_TASKS",
167 "JS3_ACTIVE",
168 "",
169 "JS3_WAIT_READ",
170 "JS3_WAIT_ISSUE",
171 "JS3_WAIT_DEPEND",
172 "JS3_WAIT_FINISH",
173 "JS4_JOBS",
174 "JS4_TASKS",
175 "JS4_ACTIVE",
176 "",
177 "JS4_WAIT_READ",
178 "JS4_WAIT_ISSUE",
179 "JS4_WAIT_DEPEND",
180 "JS4_WAIT_FINISH",
181 "JS5_JOBS",
182 "JS5_TASKS",
183 "JS5_ACTIVE",
184 "",
185 "JS5_WAIT_READ",
186 "JS5_WAIT_ISSUE",
187 "JS5_WAIT_DEPEND",
188 "JS5_WAIT_FINISH",
189 "JS6_JOBS",
190 "JS6_TASKS",
191 "JS6_ACTIVE",
192 "",
193 "JS6_WAIT_READ",
194 "JS6_WAIT_ISSUE",
195 "JS6_WAIT_DEPEND",
196 "JS6_WAIT_FINISH",
197
198 /*Tiler */
199 "",
200 "",
201 "",
202 "JOBS_PROCESSED",
203 "TRIANGLES",
204 "QUADS",
205 "POLYGONS",
206 "POINTS",
207 "LINES",
208 "VCACHE_HIT",
209 "VCACHE_MISS",
210 "FRONT_FACING",
211 "BACK_FACING",
212 "PRIM_VISIBLE",
213 "PRIM_CULLED",
214 "PRIM_CLIPPED",
215 "LEVEL0",
216 "LEVEL1",
217 "LEVEL2",
218 "LEVEL3",
219 "LEVEL4",
220 "LEVEL5",
221 "LEVEL6",
222 "LEVEL7",
223 "COMMAND_1",
224 "COMMAND_2",
225 "COMMAND_3",
226 "COMMAND_4",
227 "COMMAND_4_7",
228 "COMMAND_8_15",
229 "COMMAND_16_63",
230 "COMMAND_64",
231 "COMPRESS_IN",
232 "COMPRESS_OUT",
233 "COMPRESS_FLUSH",
234 "TIMESTAMPS",
235 "PCACHE_HIT",
236 "PCACHE_MISS",
237 "PCACHE_LINE",
238 "PCACHE_STALL",
239 "WRBUF_HIT",
240 "WRBUF_MISS",
241 "WRBUF_LINE",
242 "WRBUF_PARTIAL",
243 "WRBUF_STALL",
244 "ACTIVE",
245 "LOADING_DESC",
246 "INDEX_WAIT",
247 "INDEX_RANGE_WAIT",
248 "VERTEX_WAIT",
249 "PCACHE_WAIT",
250 "WRBUF_WAIT",
251 "BUS_READ",
252 "BUS_WRITE",
253 "",
254 "",
255 "",
256 "",
257 "",
258 "UTLB_STALL",
259 "UTLB_REPLAY_MISS",
260 "UTLB_REPLAY_FULL",
261 "UTLB_NEW_MISS",
262 "UTLB_HIT",
263
264 /* Shader Core */
265 "",
266 "",
267 "",
268 "SHADER_CORE_ACTIVE",
269 "FRAG_ACTIVE",
270 "FRAG_PRIMATIVES",
271 "FRAG_PRIMATIVES_DROPPED",
272 "FRAG_CYCLE_DESC",
273 "FRAG_CYCLES_PLR",
274 "FRAG_CYCLES_VERT",
275 "FRAG_CYCLES_TRISETUP",
276 "FRAG_CYCLES_RAST",
277 "FRAG_THREADS",
278 "FRAG_DUMMY_THREADS",
279 "FRAG_QUADS_RAST",
280 "FRAG_QUADS_EZS_TEST",
281 "FRAG_QUADS_EZS_KILLED",
282 "FRAG_QUADS_LZS_TEST",
283 "FRAG_QUADS_LZS_KILLED",
284 "FRAG_CYCLE_NO_TILE",
285 "FRAG_NUM_TILES",
286 "FRAG_TRANS_ELIM",
287 "COMPUTE_ACTIVE",
288 "COMPUTE_TASKS",
289 "COMPUTE_THREADS",
290 "COMPUTE_CYCLES_DESC",
291 "TRIPIPE_ACTIVE",
292 "ARITH_WORDS",
293 "ARITH_CYCLES_REG",
294 "ARITH_CYCLES_L0",
295 "ARITH_FRAG_DEPEND",
296 "LS_WORDS",
297 "LS_ISSUES",
298 "LS_RESTARTS",
299 "LS_REISSUES_MISS",
300 "LS_REISSUES_VD",
301 "LS_REISSUE_ATTRIB_MISS",
302 "LS_NO_WB",
303 "TEX_WORDS",
304 "TEX_BUBBLES",
305 "TEX_WORDS_L0",
306 "TEX_WORDS_DESC",
307 "TEX_THREADS",
308 "TEX_RECIRC_FMISS",
309 "TEX_RECIRC_DESC",
310 "TEX_RECIRC_MULTI",
311 "TEX_RECIRC_PMISS",
312 "TEX_RECIRC_CONF",
313 "LSC_READ_HITS",
314 "LSC_READ_MISSES",
315 "LSC_WRITE_HITS",
316 "LSC_WRITE_MISSES",
317 "LSC_ATOMIC_HITS",
318 "LSC_ATOMIC_MISSES",
319 "LSC_LINE_FETCHES",
320 "LSC_DIRTY_LINE",
321 "LSC_SNOOPS",
322 "AXI_TLB_STALL",
323 "AXI_TLB_MIESS",
324 "AXI_TLB_TRANSACTION",
325 "LS_TLB_MISS",
326 "LS_TLB_HIT",
327 "AXI_BEATS_READ",
328 "AXI_BEATS_WRITTEN",
329
330 /*L2 and MMU */
331 "",
332 "",
333 "",
334 "",
335 "MMU_HIT",
336 "MMU_NEW_MISS",
337 "MMU_REPLAY_FULL",
338 "MMU_REPLAY_MISS",
339 "MMU_TABLE_WALK",
340 "",
341 "",
342 "",
343 "",
344 "",
345 "",
346 "",
347 "UTLB_HIT",
348 "UTLB_NEW_MISS",
349 "UTLB_REPLAY_FULL",
350 "UTLB_REPLAY_MISS",
351 "UTLB_STALL",
352 "",
353 "",
354 "",
355 "",
356 "",
357 "",
358 "",
359 "",
360 "",
361 "L2_WRITE_BEATS",
362 "L2_READ_BEATS",
363 "L2_ANY_LOOKUP",
364 "L2_READ_LOOKUP",
365 "L2_SREAD_LOOKUP",
366 "L2_READ_REPLAY",
367 "L2_READ_SNOOP",
368 "L2_READ_HIT",
369 "L2_CLEAN_MISS",
370 "L2_WRITE_LOOKUP",
371 "L2_SWRITE_LOOKUP",
372 "L2_WRITE_REPLAY",
373 "L2_WRITE_SNOOP",
374 "L2_WRITE_HIT",
375 "L2_EXT_READ_FULL",
376 "L2_EXT_READ_HALF",
377 "L2_EXT_WRITE_FULL",
378 "L2_EXT_WRITE_HALF",
379 "L2_EXT_READ",
380 "L2_EXT_READ_LINE",
381 "L2_EXT_WRITE",
382 "L2_EXT_WRITE_LINE",
383 "L2_EXT_WRITE_SMALL",
384 "L2_EXT_BARRIER",
385 "L2_EXT_AR_STALL",
386 "L2_EXT_R_BUF_FULL",
387 "L2_EXT_RD_BUF_FULL",
388 "L2_EXT_R_RAW",
389 "L2_EXT_W_STALL",
390 "L2_EXT_W_BUF_FULL",
391 "L2_EXT_R_W_HAZARD",
392 "L2_TAG_HAZARD",
393 "L2_SNOOP_FULL",
394 "L2_REPLAY_FULL"
395};
396
397#define NUMBER_OF_HARDWARE_COUNTERS (sizeof(hardware_counter_names) / sizeof(hardware_counter_names[0]))
398
399#define GET_HW_BLOCK(c) (((c) >> 6) & 0x3)
400#define GET_COUNTER_OFFSET(c) ((c) & 0x3f)
401
402#if MALI_DDK_GATOR_API_VERSION == 3
403/* Opaque handles for kbase_context and kbase_hwc_dma_mapping */
404static struct mali_dd_hwcnt_handles *handles;
405
406/* Information about hardware counters */
407static struct mali_dd_hwcnt_info *in_out_info;
408
409#else
410/* Memory to dump hardware counters into */
411static void *kernel_dump_buffer;
412
413#if MALI_DDK_GATOR_API_VERSION == 2
414/* DMA state used to manage lifetime of the buffer */
415kbase_hwc_dma_mapping kernel_dump_buffer_handle;
416#endif
417
418/* kbase context and device */
419static struct kbase_context *kbcontext = NULL;
420static struct kbase_device *kbdevice = NULL;
421#endif
422
423static volatile bool kbase_device_busy = false;
424static unsigned int num_hardware_counters_enabled;
425
426/*
427 * gatorfs variables for counter enable state
428 */
429static mali_counter counters[NUMBER_OF_HARDWARE_COUNTERS];
430
431/* An array used to return the data we recorded
432 * as key,value pairs hence the *2
433 */
434static unsigned long counter_dump[NUMBER_OF_HARDWARE_COUNTERS * 2];
435
436extern mali_counter mali_activity[3];
437static const char* const mali_activity_names[] = {
438 "fragment",
439 "vertex",
440 "opencl",
441};
442
443#define SYMBOL_GET(FUNCTION, ERROR_COUNT) \
444 if(FUNCTION ## _symbol) \
445 { \
446 printk("gator: mali " #FUNCTION " symbol was already registered\n"); \
447 (ERROR_COUNT)++; \
448 } \
449 else \
450 { \
451 FUNCTION ## _symbol = symbol_get(FUNCTION); \
452 if(! FUNCTION ## _symbol) \
453 { \
454 printk("gator: mali online " #FUNCTION " symbol not found\n"); \
455 (ERROR_COUNT)++; \
456 } \
457 }
458
459#define SYMBOL_CLEANUP(FUNCTION) \
460 if(FUNCTION ## _symbol) \
461 { \
462 symbol_put(FUNCTION); \
463 FUNCTION ## _symbol = NULL; \
464 }
465
466/**
467 * Execute symbol_get for all the Mali symbols and check for success.
468 * @return the number of symbols not loaded.
469 */
470static int init_symbols(void)
471{
472 int error_count = 0;
473#if MALI_DDK_GATOR_API_VERSION == 3
474 SYMBOL_GET(kbase_dd_instr_hwcnt_dump_irq, error_count);
475 SYMBOL_GET(kbase_dd_instr_hwcnt_dump_complete, error_count);
476 SYMBOL_GET(mali_dd_hwcnt_init, error_count);
477 SYMBOL_GET(mali_dd_hwcnt_clear, error_count);
478#else
479 SYMBOL_GET(kbase_find_device, error_count);
480 SYMBOL_GET(kbase_create_context, error_count);
481 SYMBOL_GET(kbase_va_alloc, error_count);
482 SYMBOL_GET(kbase_instr_hwcnt_enable, error_count);
483 SYMBOL_GET(kbase_instr_hwcnt_clear, error_count);
484 SYMBOL_GET(kbase_instr_hwcnt_dump_irq, error_count);
485 SYMBOL_GET(kbase_instr_hwcnt_dump_complete, error_count);
486 SYMBOL_GET(kbase_instr_hwcnt_disable, error_count);
487 SYMBOL_GET(kbase_va_free, error_count);
488 SYMBOL_GET(kbase_destroy_context, error_count);
489#endif
490
491 return error_count;
492}
493
494/**
495 * Execute symbol_put for all the registered Mali symbols.
496 */
497static void clean_symbols(void)
498{
499#if MALI_DDK_GATOR_API_VERSION == 3
500 SYMBOL_CLEANUP(kbase_dd_instr_hwcnt_dump_irq);
501 SYMBOL_CLEANUP(kbase_dd_instr_hwcnt_dump_complete);
502 SYMBOL_CLEANUP(mali_dd_hwcnt_init);
503 SYMBOL_CLEANUP(mali_dd_hwcnt_clear);
504#else
505 SYMBOL_CLEANUP(kbase_find_device);
506 SYMBOL_CLEANUP(kbase_create_context);
507 SYMBOL_CLEANUP(kbase_va_alloc);
508 SYMBOL_CLEANUP(kbase_instr_hwcnt_enable);
509 SYMBOL_CLEANUP(kbase_instr_hwcnt_clear);
510 SYMBOL_CLEANUP(kbase_instr_hwcnt_dump_irq);
511 SYMBOL_CLEANUP(kbase_instr_hwcnt_dump_complete);
512 SYMBOL_CLEANUP(kbase_instr_hwcnt_disable);
513 SYMBOL_CLEANUP(kbase_va_free);
514 SYMBOL_CLEANUP(kbase_destroy_context);
515#endif
516}
517
518/**
519 * Determines whether a read should take place
520 * @param current_time The current time, obtained from getnstimeofday()
521 * @param prev_time_s The number of seconds at the previous read attempt.
522 * @param next_read_time_ns The time (in ns) when the next read should be allowed.
523 *
524 * Note that this function has been separated out here to allow it to be tested.
525 */
526static int is_read_scheduled(const struct timespec *current_time, u32 *prev_time_s, s32 *next_read_time_ns)
527{
528 /* If the current ns count rolls over a second, roll the next read time too. */
529 if (current_time->tv_sec != *prev_time_s) {
530 *next_read_time_ns = *next_read_time_ns - NSEC_PER_SEC;
531 }
532
533 /* Abort the read if the next read time has not arrived. */
534 if (current_time->tv_nsec < *next_read_time_ns) {
535 return 0;
536 }
537
538 /* Set the next read some fixed time after this one, and update the read timestamp. */
539 *next_read_time_ns = current_time->tv_nsec + READ_INTERVAL_NSEC;
540
541 *prev_time_s = current_time->tv_sec;
542 return 1;
543}
544
545static int start(void)
546{
547#if MALI_DDK_GATOR_API_VERSION < 3
548 struct kbase_uk_hwcnt_setup setup;
549 unsigned long long shadersPresent = 0;
550 u16 bitmask[] = { 0, 0, 0, 0 };
551 mali_error err;
552#endif
553 int cnt;
554
555 /* Setup HW counters */
556 num_hardware_counters_enabled = 0;
557
558 if (NUMBER_OF_HARDWARE_COUNTERS != 256) {
559 pr_debug("Unexpected number of hardware counters defined: expecting 256, got %d\n", NUMBER_OF_HARDWARE_COUNTERS);
560 }
561
562#if MALI_DDK_GATOR_API_VERSION == 3
563 /* Declare and initialise mali_dd_hwcnt_info structure */
564 in_out_info = kmalloc(sizeof(struct mali_dd_hwcnt_info), GFP_KERNEL);
565 for (cnt = 0; cnt < 4; cnt++){
566 in_out_info->bitmask[cnt] = 0;
567 }
568#endif
569 /* Calculate enable bitmasks based on counters_enabled array */
570 for (cnt = 0; cnt < NUMBER_OF_HARDWARE_COUNTERS; cnt++) {
571 const mali_counter *counter = &counters[cnt];
572 if (counter->enabled) {
573 int block = GET_HW_BLOCK(cnt);
574 int enable_bit = GET_COUNTER_OFFSET(cnt) / 4;
575#if MALI_DDK_GATOR_API_VERSION == 3
576 in_out_info->bitmask[block] |= (1 << enable_bit);
577#else
578 bitmask[block] |= (1 << enable_bit);
579#endif
580 pr_debug("gator: Mali-T6xx: hardware counter %s selected [%d]\n", hardware_counter_names[cnt], cnt);
581 num_hardware_counters_enabled++;
582 }
583 }
584
585#if MALI_DDK_GATOR_API_VERSION == 3
586 /* Create a kbase context for HW counters */
587 if (num_hardware_counters_enabled > 0) {
588 if (init_symbols() > 0) {
589 clean_symbols();
590 /* No Mali driver code entrypoints found - not a fault. */
591 return 0;
592 }
593
594 handles = mali_dd_hwcnt_init_symbol(in_out_info);
595
596 if(handles == NULL) {
597 goto out;
598 }
599
600 /* See if we can get the number of shader cores */
601 shader_present_low = (unsigned long)in_out_info->shader_present_bitmap;
602
603 kbase_device_busy = false;
604 }
605
606 return 0;
607#else
608 /* Create a kbase context for HW counters */
609 if (num_hardware_counters_enabled > 0) {
610 if (init_symbols() > 0) {
611 clean_symbols();
612 /* No Mali driver code entrypoints found - not a fault. */
613 return 0;
614 }
615
616 kbdevice = kbase_find_device_symbol(-1);
617
618 /* If we already got a context, fail */
619 if (kbcontext) {
620 pr_debug("gator: Mali-T6xx: error context already present\n");
621 goto out;
622 }
623
624 /* kbcontext will only be valid after all the Mali symbols are loaded successfully */
625 kbcontext = kbase_create_context_symbol(kbdevice);
626 if (!kbcontext) {
627 pr_debug("gator: Mali-T6xx: error creating kbase context\n");
628 goto out;
629 }
630
631
632 /* See if we can get the number of shader cores */
633 shadersPresent = kbdevice->shader_present_bitmap;
634 shader_present_low = (unsigned long)shadersPresent;
635
636 /*
637 * The amount of memory needed to store the dump (bytes)
638 * DUMP_SIZE = number of core groups
639 * * number of blocks (always 8 for midgard)
640 * * number of counters per block (always 64 for midgard)
641 * * number of bytes per counter (always 4 in midgard)
642 * For a Mali-T6xx with a single core group = 1 * 8 * 64 * 4 = 2048
643 * For a Mali-T6xx with a dual core group = 2 * 8 * 64 * 4 = 4096
644 */
645#if MALI_DDK_GATOR_API_VERSION == 1
646 kernel_dump_buffer = kbase_va_alloc_symbol(kbcontext, 4096);
647#elif MALI_DDK_GATOR_API_VERSION == 2
648 kernel_dump_buffer = kbase_va_alloc_symbol(kbcontext, 4096, &kernel_dump_buffer_handle);
649#endif
650 if (!kernel_dump_buffer) {
651 pr_debug("gator: Mali-T6xx: error trying to allocate va\n");
652 goto destroy_context;
653 }
654
655 setup.dump_buffer = (uintptr_t)kernel_dump_buffer;
656 setup.jm_bm = bitmask[JM_BLOCK];
657 setup.tiler_bm = bitmask[TILER_BLOCK];
658 setup.shader_bm = bitmask[SHADER_BLOCK];
659 setup.mmu_l2_bm = bitmask[MMU_BLOCK];
660 /* These counters do not exist on Mali-T60x */
661 setup.l3_cache_bm = 0;
662
663 /* Use kbase API to enable hardware counters and provide dump buffer */
664 err = kbase_instr_hwcnt_enable_symbol(kbcontext, &setup);
665 if (err != MALI_ERROR_NONE) {
666 pr_debug("gator: Mali-T6xx: can't setup hardware counters\n");
667 goto free_buffer;
668 }
669 pr_debug("gator: Mali-T6xx: hardware counters enabled\n");
670 kbase_instr_hwcnt_clear_symbol(kbcontext);
671 pr_debug("gator: Mali-T6xx: hardware counters cleared \n");
672
673 kbase_device_busy = false;
674 }
675
676 return 0;
677
678free_buffer:
679#if MALI_DDK_GATOR_API_VERSION == 1
680 kbase_va_free_symbol(kbcontext, kernel_dump_buffer);
681#elif MALI_DDK_GATOR_API_VERSION == 2
682 kbase_va_free_symbol(kbcontext, &kernel_dump_buffer_handle);
683#endif
684
685destroy_context:
686 kbase_destroy_context_symbol(kbcontext);
687#endif
688
689out:
690 clean_symbols();
691 return -1;
692}
693
694static void stop(void)
695{
696 unsigned int cnt;
697#if MALI_DDK_GATOR_API_VERSION == 3
698 struct mali_dd_hwcnt_handles *temp_hand;
699#else
700 struct kbase_context *temp_kbcontext;
701#endif
702
703 pr_debug("gator: Mali-T6xx: stop\n");
704
705 /* Set all counters as disabled */
706 for (cnt = 0; cnt < NUMBER_OF_HARDWARE_COUNTERS; cnt++) {
707 counters[cnt].enabled = 0;
708 }
709
710 /* Destroy the context for HW counters */
711#if MALI_DDK_GATOR_API_VERSION == 3
712 if (num_hardware_counters_enabled > 0 && handles != NULL) {
713 /*
714 * Set the global variable to NULL before destroying it, because
715 * other function will check this before using it.
716 */
717 temp_hand = handles;
718 handles = NULL;
719
720 mali_dd_hwcnt_clear_symbol(in_out_info, temp_hand);
721
722 kfree(in_out_info);
723
724#else
725 if (num_hardware_counters_enabled > 0 && kbcontext != NULL) {
726 /*
727 * Set the global variable to NULL before destroying it, because
728 * other function will check this before using it.
729 */
730 temp_kbcontext = kbcontext;
731 kbcontext = NULL;
732
733 kbase_instr_hwcnt_disable_symbol(temp_kbcontext);
734
735#if MALI_DDK_GATOR_API_VERSION == 1
736 kbase_va_free_symbol(temp_kbcontext, kernel_dump_buffer);
737#elif MALI_DDK_GATOR_API_VERSION == 2
738 kbase_va_free_symbol(temp_kbcontext, &kernel_dump_buffer_handle);
739#endif
740
741 kbase_destroy_context_symbol(temp_kbcontext);
742#endif
743
744 pr_debug("gator: Mali-T6xx: hardware counters stopped\n");
745
746 clean_symbols();
747 }
748}
749
750static int read(int **buffer)
751{
752 int cnt;
753 int len = 0;
754 u32 value = 0;
755 uint32_t success;
756
757 struct timespec current_time;
758 static u32 prev_time_s = 0;
759 static s32 next_read_time_ns = 0;
760
761 if (!on_primary_core()) {
762 return 0;
763 }
764
765 getnstimeofday(&current_time);
766
767 /*
768 * Discard reads unless a respectable time has passed. This reduces the load on the GPU without sacrificing
769 * accuracy on the Streamline display.
770 */
771 if (!is_read_scheduled(&current_time, &prev_time_s, &next_read_time_ns)) {
772 return 0;
773 }
774
775 /*
776 * Report the HW counters
777 * Only process hardware counters if at least one of the hardware counters is enabled.
778 */
779 if (num_hardware_counters_enabled > 0) {
780 const unsigned int vithar_blocks[] = {
781 0x700, /* VITHAR_JOB_MANAGER, Block 0 */
782 0x400, /* VITHAR_TILER, Block 1 */
783 0x000, /* VITHAR_SHADER_CORE, Block 2 */
784 0x500 /* VITHAR_MEMORY_SYSTEM, Block 3 */
785 };
786
787#if MALI_DDK_GATOR_API_VERSION == 3
788 if (!handles) {
789 return -1;
790 }
791
792 /* Mali symbols can be called safely since a kbcontext is valid */
793 if (kbase_dd_instr_hwcnt_dump_complete_symbol(handles, &success) == MALI_TRUE) {
794#else
795 if (!kbcontext) {
796 return -1;
797 }
798
799 /* Mali symbols can be called safely since a kbcontext is valid */
800 if (kbase_instr_hwcnt_dump_complete_symbol(kbcontext, &success) == MALI_TRUE) {
801#endif
802 kbase_device_busy = false;
803
804 if (success == MALI_TRUE) {
805 /* Cycle through hardware counters and accumulate totals */
806 for (cnt = 0; cnt < NUMBER_OF_HARDWARE_COUNTERS; cnt++) {
807 const mali_counter *counter = &counters[cnt];
808 if (counter->enabled) {
809 const int block = GET_HW_BLOCK(cnt);
810 const int counter_offset = GET_COUNTER_OFFSET(cnt);
811
812#if MALI_DDK_GATOR_API_VERSION == 3
813 const char* block_base_address = (char*)in_out_info->kernel_dump_buffer + vithar_blocks[block];
814#else
815 const char* block_base_address = (char*)kernel_dump_buffer + vithar_blocks[block];
816#endif
817
818 /* If counter belongs to shader block need to take into account all cores */
819 if (block == SHADER_BLOCK) {
820 int i = 0;
821 int shader_core_count = 0;
822 value = 0;
823
824 for (i = 0; i < 4; i++) {
825 if ((shader_present_low >> i) & 1) {
826 value += *((u32*) (block_base_address + (0x100 * i)) + counter_offset);
827 shader_core_count++;
828 }
829 }
830
831 for (i = 0; i < 4; i++) {
832 if((shader_present_low >> (i+4)) & 1) {
833 value += *((u32*)(block_base_address + (0x100 * i) + 0x800) + counter_offset);
834 shader_core_count++;
835 }
836 }
837
838 /* Need to total by number of cores to produce an average */
839 if (shader_core_count != 0) {
840 value /= shader_core_count;
841 }
842 } else {
843 value = *((u32*)block_base_address + counter_offset);
844 }
845
846 counter_dump[len++] = counter->key;
847 counter_dump[len++] = value;
848 }
849 }
850 }
851 }
852
853 if (!kbase_device_busy) {
854 kbase_device_busy = true;
855#if MALI_DDK_GATOR_API_VERSION == 3
856 kbase_dd_instr_hwcnt_dump_irq_symbol(handles);
857#else
858 kbase_instr_hwcnt_dump_irq_symbol(kbcontext);
859#endif
860 }
861 }
862
863 /* Update the buffer */
864 if (buffer) {
865 *buffer = (int *)counter_dump;
866 }
867
868 return len;
869}
870
871static int create_files(struct super_block *sb, struct dentry *root)
872{
873 unsigned int event;
874 /*
875 * Create the filesystem for all events
876 */
877 int counter_index = 0;
878
879 for (event = 0; event < ARRAY_SIZE(mali_activity); event++) {
880 if (gator_mali_create_file_system(mali_name, mali_activity_names[event], sb, root, &mali_activity[event], NULL) != 0) {
881 return -1;
882 }
883 }
884
885 for (event = 0; event < NUMBER_OF_HARDWARE_COUNTERS; event++) {
886 if (gator_mali_create_file_system(mali_name, hardware_counter_names[counter_index], sb, root, &counters[event], NULL) != 0)
887 return -1;
888 counter_index++;
889 }
890
891 return 0;
892}
893
894static struct gator_interface gator_events_mali_t6xx_interface = {
895 .create_files = create_files,
896 .start = start,
897 .stop = stop,
898 .read = read
899};
900
901int gator_events_mali_t6xx_hw_init(void)
902{
903 pr_debug("gator: Mali-T6xx: sw_counters init\n");
904
905#if GATOR_TEST
906 test_all_is_read_scheduled();
907#endif
908
909 gator_mali_initialise_counters(mali_activity, ARRAY_SIZE(mali_activity));
910 gator_mali_initialise_counters(counters, NUMBER_OF_HARDWARE_COUNTERS);
911
912 return gator_events_install(&gator_events_mali_t6xx_interface);
913}
diff --git a/drivers/gator/gator_events_mali_t6xx_hw_test.c b/drivers/gator/gator_events_mali_t6xx_hw_test.c
new file mode 100644
index 00000000000..ba6553f3540
--- /dev/null
+++ b/drivers/gator/gator_events_mali_t6xx_hw_test.c
@@ -0,0 +1,55 @@
1/**
2 * Copyright (C) ARM Limited 2012-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10/**
11 * Test functions for mali_t600_hw code.
12 */
13
14static int is_read_scheduled(const struct timespec *current_time, u32 *prev_time_s, s32 *next_read_time_ns);
15
16static int test_is_read_scheduled(u32 s, u32 ns, u32 prev_s, s32 next_ns, int expected_result, s32 expected_next_ns)
17{
18 struct timespec current_time;
19 u32 prev_time_s = prev_s;
20 s32 next_read_time_ns = next_ns;
21
22 current_time.tv_sec = s;
23 current_time.tv_nsec = ns;
24
25 if (is_read_scheduled(&current_time, &prev_time_s, &next_read_time_ns) != expected_result) {
26 printk("Failed do_read(%u, %u, %u, %d): expected %d\n", s, ns, prev_s, next_ns, expected_result);
27 return 0;
28 }
29
30 if (next_read_time_ns != expected_next_ns) {
31 printk("Failed: next_read_ns expected=%d, actual=%d\n", expected_next_ns, next_read_time_ns);
32 return 0;
33 }
34
35 return 1;
36}
37
38static void test_all_is_read_scheduled(void)
39{
40 const int HIGHEST_NS = 999999999;
41 int n_tests_passed = 0;
42
43 printk("gator: running tests on %s\n", __FILE__);
44
45 n_tests_passed += test_is_read_scheduled(0, 0, 0, 0, 1, READ_INTERVAL_NSEC); /* Null time */
46 n_tests_passed += test_is_read_scheduled(100, 1000, 0, 0, 1, READ_INTERVAL_NSEC + 1000); /* Initial values */
47
48 n_tests_passed += test_is_read_scheduled(100, HIGHEST_NS, 100, HIGHEST_NS + 500, 0, HIGHEST_NS + 500);
49 n_tests_passed += test_is_read_scheduled(101, 0001, 100, HIGHEST_NS + 500, 0, HIGHEST_NS + 500 - NSEC_PER_SEC);
50 n_tests_passed += test_is_read_scheduled(101, 600, 100, HIGHEST_NS + 500 - NSEC_PER_SEC, 1, 600 + READ_INTERVAL_NSEC);
51
52 n_tests_passed += test_is_read_scheduled(101, 600, 100, HIGHEST_NS + 500, 1, 600 + READ_INTERVAL_NSEC);
53
54 printk("gator: %d tests passed\n", n_tests_passed);
55}
diff --git a/drivers/gator/gator_events_meminfo.c b/drivers/gator/gator_events_meminfo.c
new file mode 100644
index 00000000000..c633dfdce30
--- /dev/null
+++ b/drivers/gator/gator_events_meminfo.c
@@ -0,0 +1,409 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10#include "gator.h"
11
12#include <linux/hardirq.h>
13#include <linux/kthread.h>
14#include <linux/sched.h>
15#include <linux/semaphore.h>
16#include <linux/workqueue.h>
17#include <trace/events/kmem.h>
18
19enum {
20 MEMINFO_MEMFREE,
21 MEMINFO_MEMUSED,
22 MEMINFO_BUFFERRAM,
23 MEMINFO_TOTAL,
24};
25
26enum {
27 PROC_SIZE,
28 PROC_SHARE,
29 PROC_TEXT,
30 PROC_DATA,
31 PROC_COUNT,
32};
33
34static const char * const meminfo_names[] = {
35 "Linux_meminfo_memfree",
36 "Linux_meminfo_memused",
37 "Linux_meminfo_bufferram",
38};
39
40static const char * const proc_names[] = {
41 "Linux_proc_statm_size",
42 "Linux_proc_statm_share",
43 "Linux_proc_statm_text",
44 "Linux_proc_statm_data",
45};
46
47static bool meminfo_global_enabled;
48static ulong meminfo_enabled[MEMINFO_TOTAL];
49static ulong meminfo_keys[MEMINFO_TOTAL];
50static long long meminfo_buffer[2 * (MEMINFO_TOTAL + 2)];
51static int meminfo_length = 0;
52static bool new_data_avail;
53
54static bool proc_global_enabled;
55static ulong proc_enabled[PROC_COUNT];
56static ulong proc_keys[PROC_COUNT];
57static DEFINE_PER_CPU(long long, proc_buffer[2 * (PROC_COUNT + 3)]);
58
59static int gator_meminfo_func(void *data);
60static bool gator_meminfo_run;
61// Initialize semaphore unlocked to initialize memory values
62#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
63static DECLARE_MUTEX(gator_meminfo_sem);
64#else
65static DEFINE_SEMAPHORE(gator_meminfo_sem);
66#endif
67
68#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
69GATOR_DEFINE_PROBE(mm_page_free_direct, TP_PROTO(struct page *page, unsigned int order))
70#else
71GATOR_DEFINE_PROBE(mm_page_free, TP_PROTO(struct page *page, unsigned int order))
72#endif
73{
74 up(&gator_meminfo_sem);
75}
76
77#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
78GATOR_DEFINE_PROBE(mm_pagevec_free, TP_PROTO(struct page *page, int cold))
79#else
80GATOR_DEFINE_PROBE(mm_page_free_batched, TP_PROTO(struct page *page, int cold))
81#endif
82{
83 up(&gator_meminfo_sem);
84}
85
86GATOR_DEFINE_PROBE(mm_page_alloc, TP_PROTO(struct page *page, unsigned int order, gfp_t gfp_flags, int migratetype))
87{
88 up(&gator_meminfo_sem);
89}
90
91static int gator_events_meminfo_create_files(struct super_block *sb, struct dentry *root)
92{
93 struct dentry *dir;
94 int i;
95
96 for (i = 0; i < MEMINFO_TOTAL; i++) {
97 dir = gatorfs_mkdir(sb, root, meminfo_names[i]);
98 if (!dir) {
99 return -1;
100 }
101 gatorfs_create_ulong(sb, dir, "enabled", &meminfo_enabled[i]);
102 gatorfs_create_ro_ulong(sb, dir, "key", &meminfo_keys[i]);
103 }
104
105 for (i = 0; i < PROC_COUNT; ++i) {
106 dir = gatorfs_mkdir(sb, root, proc_names[i]);
107 if (!dir) {
108 return -1;
109 }
110 gatorfs_create_ulong(sb, dir, "enabled", &proc_enabled[i]);
111 gatorfs_create_ro_ulong(sb, dir, "key", &proc_keys[i]);
112 }
113
114 return 0;
115}
116
117static int gator_events_meminfo_start(void)
118{
119 int i;
120
121 new_data_avail = false;
122 meminfo_global_enabled = 0;
123 for (i = 0; i < MEMINFO_TOTAL; i++) {
124 if (meminfo_enabled[i]) {
125 meminfo_global_enabled = 1;
126 break;
127 }
128 }
129
130 proc_global_enabled = 0;
131 for (i = 0; i < PROC_COUNT; ++i) {
132 if (proc_enabled[i]) {
133 proc_global_enabled = 1;
134 break;
135 }
136 }
137 if (meminfo_enabled[MEMINFO_MEMUSED]) {
138 proc_global_enabled = 1;
139 }
140
141 if (meminfo_global_enabled == 0)
142 return 0;
143
144#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
145 if (GATOR_REGISTER_TRACE(mm_page_free_direct))
146#else
147 if (GATOR_REGISTER_TRACE(mm_page_free))
148#endif
149 goto mm_page_free_exit;
150#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
151 if (GATOR_REGISTER_TRACE(mm_pagevec_free))
152#else
153 if (GATOR_REGISTER_TRACE(mm_page_free_batched))
154#endif
155 goto mm_page_free_batched_exit;
156 if (GATOR_REGISTER_TRACE(mm_page_alloc))
157 goto mm_page_alloc_exit;
158
159 // Start worker thread
160 gator_meminfo_run = true;
161 // Since the mutex starts unlocked, memory values will be initialized
162 if (IS_ERR(kthread_run(gator_meminfo_func, NULL, "gator_meminfo")))
163 goto kthread_run_exit;
164
165 return 0;
166
167kthread_run_exit:
168 GATOR_UNREGISTER_TRACE(mm_page_alloc);
169mm_page_alloc_exit:
170#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
171 GATOR_UNREGISTER_TRACE(mm_pagevec_free);
172#else
173 GATOR_UNREGISTER_TRACE(mm_page_free_batched);
174#endif
175mm_page_free_batched_exit:
176#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
177 GATOR_UNREGISTER_TRACE(mm_page_free_direct);
178#else
179 GATOR_UNREGISTER_TRACE(mm_page_free);
180#endif
181mm_page_free_exit:
182 return -1;
183}
184
185static void gator_events_meminfo_stop(void)
186{
187 if (meminfo_global_enabled) {
188#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
189 GATOR_UNREGISTER_TRACE(mm_page_free_direct);
190 GATOR_UNREGISTER_TRACE(mm_pagevec_free);
191#else
192 GATOR_UNREGISTER_TRACE(mm_page_free);
193 GATOR_UNREGISTER_TRACE(mm_page_free_batched);
194#endif
195 GATOR_UNREGISTER_TRACE(mm_page_alloc);
196
197 // Stop worker thread
198 gator_meminfo_run = false;
199 up(&gator_meminfo_sem);
200 }
201}
202
203// Must be run in process context as the kernel function si_meminfo() can sleep
204static int gator_meminfo_func(void *data)
205{
206 struct sysinfo info;
207 int i, len;
208 unsigned long long value;
209
210 for (;;) {
211 if (down_killable(&gator_meminfo_sem)) {
212 break;
213 }
214
215 // Eat up any pending events
216 while (!down_trylock(&gator_meminfo_sem));
217
218 if (!gator_meminfo_run) {
219 break;
220 }
221
222 meminfo_length = len = 0;
223
224 si_meminfo(&info);
225 for (i = 0; i < MEMINFO_TOTAL; i++) {
226 if (meminfo_enabled[i]) {
227 switch (i) {
228 case MEMINFO_MEMFREE:
229 value = info.freeram * PAGE_SIZE;
230 break;
231 case MEMINFO_MEMUSED:
232 // pid -1 means system wide
233 meminfo_buffer[len++] = 1;
234 meminfo_buffer[len++] = -1;
235 // Emit value
236 meminfo_buffer[len++] = meminfo_keys[MEMINFO_MEMUSED];
237 meminfo_buffer[len++] = (info.totalram - info.freeram) * PAGE_SIZE;
238 // Clear pid
239 meminfo_buffer[len++] = 1;
240 meminfo_buffer[len++] = 0;
241 continue;
242 case MEMINFO_BUFFERRAM:
243 value = info.bufferram * PAGE_SIZE;
244 break;
245 default:
246 value = 0;
247 break;
248 }
249 meminfo_buffer[len++] = meminfo_keys[i];
250 meminfo_buffer[len++] = value;
251 }
252 }
253
254 meminfo_length = len;
255 new_data_avail = true;
256 }
257
258 return 0;
259}
260
261static int gator_events_meminfo_read(long long **buffer)
262{
263 if (!on_primary_core() || !meminfo_global_enabled)
264 return 0;
265
266 if (!new_data_avail)
267 return 0;
268
269 new_data_avail = false;
270
271 if (buffer)
272 *buffer = meminfo_buffer;
273
274 return meminfo_length;
275}
276
277#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34) && LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)
278
279static inline unsigned long gator_get_mm_counter(struct mm_struct *mm, int member)
280{
281#ifdef SPLIT_RSS_COUNTING
282 long val = atomic_long_read(&mm->rss_stat.count[member]);
283 if (val < 0)
284 val = 0;
285 return (unsigned long)val;
286#else
287#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0)
288 return mm->rss_stat.count[member];
289#else
290 return atomic_long_read(&mm->rss_stat.count[member]);
291#endif
292#endif
293}
294
295#define get_mm_counter(mm, member) gator_get_mm_counter(mm, member)
296
297#endif
298
299static int gator_events_meminfo_read_proc(long long **buffer, struct task_struct *task)
300{
301 struct mm_struct *mm;
302 u64 share = 0;
303 int i;
304 long long value;
305 int len = 0;
306 int cpu = get_physical_cpu();
307 long long *buf = per_cpu(proc_buffer, cpu);
308
309 if (!proc_global_enabled) {
310 return 0;
311 }
312
313 // Collect the memory stats of the process instead of the thread
314 if (task->group_leader != NULL) {
315 task = task->group_leader;
316 }
317
318 // get_task_mm/mmput is not needed in this context because the task and it's mm are required as part of the sched_switch
319 mm = task->mm;
320 if (mm == NULL) {
321 return 0;
322 }
323
324 // Derived from task_statm in fs/proc/task_mmu.c
325 if (meminfo_enabled[MEMINFO_MEMUSED] || proc_enabled[PROC_SHARE]) {
326 share = get_mm_counter(mm,
327#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
328 file_rss
329#else
330 MM_FILEPAGES
331#endif
332 );
333 }
334
335 // key of 1 indicates a pid
336 buf[len++] = 1;
337 buf[len++] = task->pid;
338
339 for (i = 0; i < PROC_COUNT; ++i) {
340 if (proc_enabled[i]) {
341 switch (i) {
342 case PROC_SIZE:
343 value = mm->total_vm;
344 break;
345 case PROC_SHARE:
346 value = share;
347 break;
348 case PROC_TEXT:
349 value = (PAGE_ALIGN(mm->end_code) - (mm->start_code & PAGE_MASK)) >> PAGE_SHIFT;
350 break;
351 case PROC_DATA:
352 value = mm->total_vm - mm->shared_vm;
353 break;
354 }
355
356 buf[len++] = proc_keys[i];
357 buf[len++] = value * PAGE_SIZE;
358 }
359 }
360
361 if (meminfo_enabled[MEMINFO_MEMUSED]) {
362 value = share + get_mm_counter(mm,
363#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
364 anon_rss
365#else
366 MM_ANONPAGES
367#endif
368 );
369 // Send resident for this pid
370 buf[len++] = meminfo_keys[MEMINFO_MEMUSED];
371 buf[len++] = value * PAGE_SIZE;
372 }
373
374 // Clear pid
375 buf[len++] = 1;
376 buf[len++] = 0;
377
378 if (buffer)
379 *buffer = buf;
380
381 return len;
382}
383
384static struct gator_interface gator_events_meminfo_interface = {
385 .create_files = gator_events_meminfo_create_files,
386 .start = gator_events_meminfo_start,
387 .stop = gator_events_meminfo_stop,
388 .read64 = gator_events_meminfo_read,
389 .read_proc = gator_events_meminfo_read_proc,
390};
391
392int gator_events_meminfo_init(void)
393{
394 int i;
395
396 meminfo_global_enabled = 0;
397 for (i = 0; i < MEMINFO_TOTAL; i++) {
398 meminfo_enabled[i] = 0;
399 meminfo_keys[i] = gator_events_get_key();
400 }
401
402 proc_global_enabled = 0;
403 for (i = 0; i < PROC_COUNT; ++i) {
404 proc_enabled[i] = 0;
405 proc_keys[i] = gator_events_get_key();
406 }
407
408 return gator_events_install(&gator_events_meminfo_interface);
409}
diff --git a/drivers/gator/gator_events_mmapped.c b/drivers/gator/gator_events_mmapped.c
new file mode 100644
index 00000000000..5bc01c42c3a
--- /dev/null
+++ b/drivers/gator/gator_events_mmapped.c
@@ -0,0 +1,209 @@
1/*
2 * Example events provider
3 *
4 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * Similar entries to those below must be present in the events.xml file.
11 * To add them to the events.xml, create an events-mmap.xml with the
12 * following contents and rebuild gatord:
13 *
14 * <category name="mmapped">
15 * <event counter="mmapped_cnt0" title="Simulated1" name="Sine" display="maximum" class="absolute" description="Sort-of-sine"/>
16 * <event counter="mmapped_cnt1" title="Simulated2" name="Triangle" display="maximum" class="absolute" description="Triangular wave"/>
17 * <event counter="mmapped_cnt2" title="Simulated3" name="PWM" display="maximum" class="absolute" description="PWM Signal"/>
18 * </category>
19 *
20 * When adding custom events, be sure to do the following:
21 * - add any needed .c files to the gator driver Makefile
22 * - call gator_events_install in the events init function
23 * - add the init function to GATOR_EVENTS_LIST in gator_main.c
24 * - add a new events-*.xml file to the gator daemon and rebuild
25 *
26 * Troubleshooting:
27 * - verify the new events are part of events.xml, which is created when building the daemon
28 * - verify the new events exist at /dev/gator/events/ once gatord is launched
29 * - verify the counter name in the XML matches the name at /dev/gator/events
30 */
31
32#include <linux/init.h>
33#include <linux/io.h>
34#include <linux/ratelimit.h>
35
36#include "gator.h"
37
38#define MMAPPED_COUNTERS_NUM 3
39
40static int mmapped_global_enabled;
41
42static struct {
43 unsigned long enabled;
44 unsigned long key;
45} mmapped_counters[MMAPPED_COUNTERS_NUM];
46
47static int mmapped_buffer[MMAPPED_COUNTERS_NUM * 2];
48
49static s64 prev_time;
50
51/* Adds mmapped_cntX directories and enabled, event, and key files to /dev/gator/events */
52static int gator_events_mmapped_create_files(struct super_block *sb,
53 struct dentry *root)
54{
55 int i;
56
57 for (i = 0; i < MMAPPED_COUNTERS_NUM; i++) {
58 char buf[16];
59 struct dentry *dir;
60
61 snprintf(buf, sizeof(buf), "mmapped_cnt%d", i);
62 dir = gatorfs_mkdir(sb, root, buf);
63 if (WARN_ON(!dir))
64 return -1;
65 gatorfs_create_ulong(sb, dir, "enabled",
66 &mmapped_counters[i].enabled);
67 gatorfs_create_ro_ulong(sb, dir, "key",
68 &mmapped_counters[i].key);
69 }
70
71 return 0;
72}
73
74static int gator_events_mmapped_start(void)
75{
76 int i;
77 struct timespec ts;
78
79 getnstimeofday(&ts);
80 prev_time = timespec_to_ns(&ts);
81
82 mmapped_global_enabled = 0;
83 for (i = 0; i < MMAPPED_COUNTERS_NUM; i++) {
84 if (mmapped_counters[i].enabled) {
85 mmapped_global_enabled = 1;
86 break;
87 }
88 }
89
90 return 0;
91}
92
93static void gator_events_mmapped_stop(void)
94{
95}
96
97/* This function "simulates" counters, generating values of fancy
98 * functions like sine or triangle... */
99static int mmapped_simulate(int counter, int delta_in_us)
100{
101 int result = 0;
102
103 switch (counter) {
104 case 0: /* sort-of-sine */
105 {
106 static int t = 0;
107 int x;
108
109 t += delta_in_us;
110 if (t > 2048000)
111 t = 0;
112
113 if (t % 1024000 < 512000)
114 x = 512000 - (t % 512000);
115 else
116 x = t % 512000;
117
118 result = 32 * x / 512000;
119 result = result * result;
120
121 if (t < 1024000)
122 result = 1922 - result;
123 }
124 break;
125 case 1: /* triangle */
126 {
127 static int v, d = 1;
128
129 v = v + d * delta_in_us;
130 if (v < 0) {
131 v = 0;
132 d = 1;
133 } else if (v > 1000000) {
134 v = 1000000;
135 d = -1;
136 }
137
138 result = v;
139 }
140 break;
141 case 2: /* PWM signal */
142 {
143 static int dc, x, t = 0;
144
145 t += delta_in_us;
146 if (t > 1000000)
147 t = 0;
148 if (x / 1000000 != (x + delta_in_us) / 1000000)
149 dc = (dc + 100000) % 1000000;
150 x += delta_in_us;
151
152 result = t < dc ? 0 : 10;
153 }
154 break;
155 }
156
157 return result;
158}
159
160static int gator_events_mmapped_read(int **buffer)
161{
162 int i;
163 int len = 0;
164 int delta_in_us;
165 struct timespec ts;
166 s64 time;
167
168 /* System wide counters - read from one core only */
169 if (!on_primary_core() || !mmapped_global_enabled)
170 return 0;
171
172 getnstimeofday(&ts);
173 time = timespec_to_ns(&ts);
174 delta_in_us = (int)(time - prev_time) / 1000;
175 prev_time = time;
176
177 for (i = 0; i < MMAPPED_COUNTERS_NUM; i++) {
178 if (mmapped_counters[i].enabled) {
179 mmapped_buffer[len++] = mmapped_counters[i].key;
180 mmapped_buffer[len++] =
181 mmapped_simulate(i, delta_in_us);
182 }
183 }
184
185 if (buffer)
186 *buffer = mmapped_buffer;
187
188 return len;
189}
190
191static struct gator_interface gator_events_mmapped_interface = {
192 .create_files = gator_events_mmapped_create_files,
193 .start = gator_events_mmapped_start,
194 .stop = gator_events_mmapped_stop,
195 .read = gator_events_mmapped_read,
196};
197
198/* Must not be static! */
199int __init gator_events_mmapped_init(void)
200{
201 int i;
202
203 for (i = 0; i < MMAPPED_COUNTERS_NUM; i++) {
204 mmapped_counters[i].enabled = 0;
205 mmapped_counters[i].key = gator_events_get_key();
206 }
207
208 return gator_events_install(&gator_events_mmapped_interface);
209}
diff --git a/drivers/gator/gator_events_net.c b/drivers/gator/gator_events_net.c
new file mode 100644
index 00000000000..11c10e37551
--- /dev/null
+++ b/drivers/gator/gator_events_net.c
@@ -0,0 +1,172 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10#include "gator.h"
11#include <linux/netdevice.h>
12#include <linux/hardirq.h>
13
14#define NETRX 0
15#define NETTX 1
16#define TOTALNET 2
17
18static ulong netrx_enabled;
19static ulong nettx_enabled;
20static ulong netrx_key;
21static ulong nettx_key;
22static int rx_total, tx_total;
23static ulong netPrev[TOTALNET];
24static int netGet[TOTALNET * 4];
25
26static struct timer_list net_wake_up_timer;
27
28// Must be run in process context as the kernel function dev_get_stats() can sleep
29static void get_network_stats(struct work_struct *wsptr)
30{
31 int rx = 0, tx = 0;
32 struct net_device *dev;
33
34 for_each_netdev(&init_net, dev) {
35#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
36 const struct net_device_stats *stats = dev_get_stats(dev);
37#else
38 struct rtnl_link_stats64 temp;
39 const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp);
40#endif
41 rx += stats->rx_bytes;
42 tx += stats->tx_bytes;
43 }
44 rx_total = rx;
45 tx_total = tx;
46}
47
48DECLARE_WORK(wq_get_stats, get_network_stats);
49
50static void net_wake_up_handler(unsigned long unused_data)
51{
52 // had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater
53 schedule_work(&wq_get_stats);
54}
55
56static void calculate_delta(int *rx, int *tx)
57{
58 int rx_calc, tx_calc;
59
60 rx_calc = (int)(rx_total - netPrev[NETRX]);
61 if (rx_calc < 0)
62 rx_calc = 0;
63 netPrev[NETRX] += rx_calc;
64
65 tx_calc = (int)(tx_total - netPrev[NETTX]);
66 if (tx_calc < 0)
67 tx_calc = 0;
68 netPrev[NETTX] += tx_calc;
69
70 *rx = rx_calc;
71 *tx = tx_calc;
72}
73
74static int gator_events_net_create_files(struct super_block *sb, struct dentry *root)
75{
76 // Network counters are not currently supported in RT-Preempt full because mod_timer is used
77#ifndef CONFIG_PREEMPT_RT_FULL
78 struct dentry *dir;
79
80 dir = gatorfs_mkdir(sb, root, "Linux_net_rx");
81 if (!dir) {
82 return -1;
83 }
84 gatorfs_create_ulong(sb, dir, "enabled", &netrx_enabled);
85 gatorfs_create_ro_ulong(sb, dir, "key", &netrx_key);
86
87 dir = gatorfs_mkdir(sb, root, "Linux_net_tx");
88 if (!dir) {
89 return -1;
90 }
91 gatorfs_create_ulong(sb, dir, "enabled", &nettx_enabled);
92 gatorfs_create_ro_ulong(sb, dir, "key", &nettx_key);
93#endif
94
95 return 0;
96}
97
98static int gator_events_net_start(void)
99{
100 get_network_stats(0);
101 netPrev[NETRX] = rx_total;
102 netPrev[NETTX] = tx_total;
103#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
104 setup_timer(&net_wake_up_timer, net_wake_up_handler, 0);
105#else
106 setup_deferrable_timer_on_stack(&net_wake_up_timer, net_wake_up_handler, 0);
107#endif
108 return 0;
109}
110
111static void gator_events_net_stop(void)
112{
113 del_timer_sync(&net_wake_up_timer);
114 netrx_enabled = 0;
115 nettx_enabled = 0;
116}
117
118static int gator_events_net_read(int **buffer)
119{
120 int len, rx_delta, tx_delta;
121 static int last_rx_delta = 0, last_tx_delta = 0;
122
123 if (!on_primary_core())
124 return 0;
125
126 if (!netrx_enabled && !nettx_enabled)
127 return 0;
128
129 mod_timer(&net_wake_up_timer, jiffies + 1);
130
131 calculate_delta(&rx_delta, &tx_delta);
132
133 len = 0;
134 if (netrx_enabled && last_rx_delta != rx_delta) {
135 last_rx_delta = rx_delta;
136 netGet[len++] = netrx_key;
137 netGet[len++] = 0; // indicates to Streamline that rx_delta bytes were transmitted now, not since the last message
138 netGet[len++] = netrx_key;
139 netGet[len++] = rx_delta;
140 }
141
142 if (nettx_enabled && last_tx_delta != tx_delta) {
143 last_tx_delta = tx_delta;
144 netGet[len++] = nettx_key;
145 netGet[len++] = 0; // indicates to Streamline that tx_delta bytes were transmitted now, not since the last message
146 netGet[len++] = nettx_key;
147 netGet[len++] = tx_delta;
148 }
149
150 if (buffer)
151 *buffer = netGet;
152
153 return len;
154}
155
156static struct gator_interface gator_events_net_interface = {
157 .create_files = gator_events_net_create_files,
158 .start = gator_events_net_start,
159 .stop = gator_events_net_stop,
160 .read = gator_events_net_read,
161};
162
163int gator_events_net_init(void)
164{
165 netrx_key = gator_events_get_key();
166 nettx_key = gator_events_get_key();
167
168 netrx_enabled = 0;
169 nettx_enabled = 0;
170
171 return gator_events_install(&gator_events_net_interface);
172}
diff --git a/drivers/gator/gator_events_perf_pmu.c b/drivers/gator/gator_events_perf_pmu.c
new file mode 100644
index 00000000000..06bbad5b10c
--- /dev/null
+++ b/drivers/gator/gator_events_perf_pmu.c
@@ -0,0 +1,587 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "gator.h"
10
11// gator_events_armvX.c is used for Linux 2.6.x
12#if GATOR_PERF_PMU_SUPPORT
13
14#include <linux/io.h>
15#ifdef CONFIG_OF
16#include <linux/of_address.h>
17#endif
18#include <linux/perf_event.h>
19#include <linux/slab.h>
20
21extern bool event_based_sampling;
22
23// Maximum number of per-core counters - currently reserves enough space for two full hardware PMUs for big.LITTLE
24#define CNTMAX 16
25#define CCI_400 4
26// Maximum number of uncore counters
27// + 1 for the cci-400 cycles counter
28#define UCCNT (CCI_400 + 1)
29
30// Default to 0 if unable to probe the revision which was the previous behavior
31#define DEFAULT_CCI_REVISION 0
32
33// A gator_attr is needed for every counter
34struct gator_attr {
35 // Set once in gator_events_perf_pmu_*_init - the name of the event in the gatorfs
36 char name[40];
37 // Exposed in gatorfs - set by gatord to enable this counter
38 unsigned long enabled;
39 // Set once in gator_events_perf_pmu_*_init - the perf type to use, see perf_type_id in the perf_event.h header file.
40 unsigned long type;
41 // Exposed in gatorfs - set by gatord to select the event to collect
42 unsigned long event;
43 // Exposed in gatorfs - set by gatord with the sample period to use and enable EBS for this counter
44 unsigned long count;
45 // Exposed as read only in gatorfs - set once in __attr_init as the key to use in the APC data
46 unsigned long key;
47};
48
49// Per-core counter attributes
50static struct gator_attr attrs[CNTMAX];
51// Number of initialized per-core counters
52static int attr_count;
53// Uncore counter attributes
54static struct gator_attr uc_attrs[UCCNT];
55// Number of initialized uncore counters
56static int uc_attr_count;
57
58struct gator_event {
59 int curr;
60 int prev;
61 int prev_delta;
62 bool zero;
63 struct perf_event *pevent;
64 struct perf_event_attr *pevent_attr;
65};
66
67static DEFINE_PER_CPU(struct gator_event[CNTMAX], events);
68static struct gator_event uc_events[UCCNT];
69static DEFINE_PER_CPU(int[(CNTMAX + UCCNT)*2], perf_cnt);
70
71static void gator_events_perf_pmu_stop(void);
72
73static int __create_files(struct super_block *sb, struct dentry *root, struct gator_attr *const attr)
74{
75 struct dentry *dir;
76
77 if (attr->name[0] == '\0') {
78 return 0;
79 }
80 dir = gatorfs_mkdir(sb, root, attr->name);
81 if (!dir) {
82 return -1;
83 }
84 gatorfs_create_ulong(sb, dir, "enabled", &attr->enabled);
85 gatorfs_create_ulong(sb, dir, "count", &attr->count);
86 gatorfs_create_ro_ulong(sb, dir, "key", &attr->key);
87 gatorfs_create_ulong(sb, dir, "event", &attr->event);
88
89 return 0;
90}
91
92static int gator_events_perf_pmu_create_files(struct super_block *sb, struct dentry *root)
93{
94 int cnt;
95
96 for (cnt = 0; cnt < attr_count; cnt++) {
97 if (__create_files(sb, root, &attrs[cnt]) != 0) {
98 return -1;
99 }
100 }
101
102 for (cnt = 0; cnt < uc_attr_count; cnt++) {
103 if (__create_files(sb, root, &uc_attrs[cnt]) != 0) {
104 return -1;
105 }
106 }
107
108 return 0;
109}
110
111#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)
112static void ebs_overflow_handler(struct perf_event *event, int unused, struct perf_sample_data *data, struct pt_regs *regs)
113#else
114static void ebs_overflow_handler(struct perf_event *event, struct perf_sample_data *data, struct pt_regs *regs)
115#endif
116{
117 gator_backtrace_handler(regs);
118}
119
120#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)
121static void dummy_handler(struct perf_event *event, int unused, struct perf_sample_data *data, struct pt_regs *regs)
122#else
123static void dummy_handler(struct perf_event *event, struct perf_sample_data *data, struct pt_regs *regs)
124#endif
125{
126// Required as perf_event_create_kernel_counter() requires an overflow handler, even though all we do is poll
127}
128
129static int gator_events_perf_pmu_read(int **buffer);
130
131static int gator_events_perf_pmu_online(int **buffer, bool migrate)
132{
133 return gator_events_perf_pmu_read(buffer);
134}
135
136static void __online_dispatch(int cpu, bool migrate, struct gator_attr *const attr, struct gator_event *const event)
137{
138 perf_overflow_handler_t handler;
139
140 event->zero = true;
141
142 if (event->pevent != NULL || event->pevent_attr == 0 || migrate) {
143 return;
144 }
145
146 if (attr->count > 0) {
147 handler = ebs_overflow_handler;
148 } else {
149 handler = dummy_handler;
150 }
151
152#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)
153 event->pevent = perf_event_create_kernel_counter(event->pevent_attr, cpu, 0, handler);
154#else
155 event->pevent = perf_event_create_kernel_counter(event->pevent_attr, cpu, 0, handler, 0);
156#endif
157 if (IS_ERR(event->pevent)) {
158 pr_debug("gator: unable to online a counter on cpu %d\n", cpu);
159 event->pevent = NULL;
160 return;
161 }
162
163 if (event->pevent->state != PERF_EVENT_STATE_ACTIVE) {
164 pr_debug("gator: inactive counter on cpu %d\n", cpu);
165 perf_event_release_kernel(event->pevent);
166 event->pevent = NULL;
167 return;
168 }
169}
170
171static void gator_events_perf_pmu_online_dispatch(int cpu, bool migrate)
172{
173 int cnt;
174
175 cpu = pcpu_to_lcpu(cpu);
176
177 for (cnt = 0; cnt < attr_count; cnt++) {
178 __online_dispatch(cpu, migrate, &attrs[cnt], &per_cpu(events, cpu)[cnt]);
179 }
180
181 if (cpu == 0) {
182 for (cnt = 0; cnt < uc_attr_count; cnt++) {
183 __online_dispatch(cpu, migrate, &uc_attrs[cnt], &uc_events[cnt]);
184 }
185 }
186}
187
188static void __offline_dispatch(int cpu, struct gator_event *const event)
189{
190 struct perf_event *pe = NULL;
191
192 if (event->pevent) {
193 pe = event->pevent;
194 event->pevent = NULL;
195 }
196
197 if (pe) {
198 perf_event_release_kernel(pe);
199 }
200}
201
202static void gator_events_perf_pmu_offline_dispatch(int cpu, bool migrate)
203{
204 int cnt;
205
206 if (migrate) {
207 return;
208 }
209 cpu = pcpu_to_lcpu(cpu);
210
211 for (cnt = 0; cnt < attr_count; cnt++) {
212 __offline_dispatch(cpu, &per_cpu(events, cpu)[cnt]);
213 }
214
215 if (cpu == 0) {
216 for (cnt = 0; cnt < uc_attr_count; cnt++) {
217 __offline_dispatch(cpu, &uc_events[cnt]);
218 }
219 }
220}
221
222static int __check_ebs(struct gator_attr *const attr)
223{
224 if (attr->count > 0) {
225 if (!event_based_sampling) {
226 event_based_sampling = true;
227 } else {
228 printk(KERN_WARNING "gator: Only one ebs counter is allowed\n");
229 return -1;
230 }
231 }
232
233 return 0;
234}
235
236static int __start(struct gator_attr *const attr, struct gator_event *const event)
237{
238 u32 size = sizeof(struct perf_event_attr);
239
240 event->pevent = NULL;
241 if (!attr->enabled) { // Skip disabled counters
242 return 0;
243 }
244
245 event->prev = 0;
246 event->curr = 0;
247 event->prev_delta = 0;
248 event->pevent_attr = kmalloc(size, GFP_KERNEL);
249 if (!event->pevent_attr) {
250 gator_events_perf_pmu_stop();
251 return -1;
252 }
253
254 memset(event->pevent_attr, 0, size);
255 event->pevent_attr->type = attr->type;
256 event->pevent_attr->size = size;
257 event->pevent_attr->config = attr->event;
258 event->pevent_attr->sample_period = attr->count;
259 event->pevent_attr->pinned = 1;
260
261 return 0;
262}
263
264static int gator_events_perf_pmu_start(void)
265{
266 int cnt, cpu;
267
268 event_based_sampling = false;
269 for (cnt = 0; cnt < attr_count; cnt++) {
270 if (__check_ebs(&attrs[cnt]) != 0) {
271 return -1;
272 }
273 }
274
275 for (cnt = 0; cnt < uc_attr_count; cnt++) {
276 if (__check_ebs(&uc_attrs[cnt]) != 0) {
277 return -1;
278 }
279 }
280
281 for_each_present_cpu(cpu) {
282 for (cnt = 0; cnt < attr_count; cnt++) {
283 if (__start(&attrs[cnt], &per_cpu(events, cpu)[cnt]) != 0) {
284 return -1;
285 }
286 }
287 }
288
289 for (cnt = 0; cnt < uc_attr_count; cnt++) {
290 if (__start(&uc_attrs[cnt], &uc_events[cnt]) != 0) {
291 return -1;
292 }
293 }
294
295 return 0;
296}
297
298static void __event_stop(struct gator_event *const event)
299{
300 if (event->pevent_attr) {
301 kfree(event->pevent_attr);
302 event->pevent_attr = NULL;
303 }
304}
305
306static void __attr_stop(struct gator_attr *const attr)
307{
308 attr->enabled = 0;
309 attr->event = 0;
310 attr->count = 0;
311}
312
313static void gator_events_perf_pmu_stop(void)
314{
315 unsigned int cnt, cpu;
316
317 for_each_present_cpu(cpu) {
318 for (cnt = 0; cnt < attr_count; cnt++) {
319 __event_stop(&per_cpu(events, cpu)[cnt]);
320 }
321 }
322
323 for (cnt = 0; cnt < uc_attr_count; cnt++) {
324 __event_stop(&uc_events[cnt]);
325 }
326
327 for (cnt = 0; cnt < attr_count; cnt++) {
328 __attr_stop(&attrs[cnt]);
329 }
330
331 for (cnt = 0; cnt < uc_attr_count; cnt++) {
332 __attr_stop(&uc_attrs[cnt]);
333 }
334}
335
336static void __read(int *const len, int cpu, struct gator_attr *const attr, struct gator_event *const event)
337{
338 int delta;
339
340 struct perf_event *const ev = event->pevent;
341 if (ev != NULL && ev->state == PERF_EVENT_STATE_ACTIVE) {
342 /* After creating the perf counter in __online_dispatch, there
343 * is a race condition between gator_events_perf_pmu_online and
344 * gator_events_perf_pmu_read. So have
345 * gator_events_perf_pmu_online call gator_events_perf_pmu_read
346 * and in __read check to see if it's the first call after
347 * __online_dispatch and if so, run the online code.
348 */
349 if (event->zero) {
350 ev->pmu->read(ev);
351 event->prev = event->curr = local64_read(&ev->count);
352 event->prev_delta = 0;
353 per_cpu(perf_cnt, cpu)[(*len)++] = attr->key;
354 per_cpu(perf_cnt, cpu)[(*len)++] = 0;
355 event->zero = false;
356 } else {
357 ev->pmu->read(ev);
358 event->curr = local64_read(&ev->count);
359 delta = event->curr - event->prev;
360 if (delta != 0 || delta != event->prev_delta) {
361 event->prev_delta = delta;
362 event->prev = event->curr;
363 per_cpu(perf_cnt, cpu)[(*len)++] = attr->key;
364 if (delta < 0) {
365 delta *= -1;
366 }
367 per_cpu(perf_cnt, cpu)[(*len)++] = delta;
368 }
369 }
370 }
371}
372
373static int gator_events_perf_pmu_read(int **buffer)
374{
375 int cnt, len = 0;
376 const int cpu = get_logical_cpu();
377
378 for (cnt = 0; cnt < attr_count; cnt++) {
379 __read(&len, cpu, &attrs[cnt], &per_cpu(events, cpu)[cnt]);
380 }
381
382 if (cpu == 0) {
383 for (cnt = 0; cnt < uc_attr_count; cnt++) {
384 __read(&len, cpu, &uc_attrs[cnt], &uc_events[cnt]);
385 }
386 }
387
388 if (buffer) {
389 *buffer = per_cpu(perf_cnt, cpu);
390 }
391
392 return len;
393}
394
395static struct gator_interface gator_events_perf_pmu_interface = {
396 .create_files = gator_events_perf_pmu_create_files,
397 .start = gator_events_perf_pmu_start,
398 .stop = gator_events_perf_pmu_stop,
399 .online = gator_events_perf_pmu_online,
400 .online_dispatch = gator_events_perf_pmu_online_dispatch,
401 .offline_dispatch = gator_events_perf_pmu_offline_dispatch,
402 .read = gator_events_perf_pmu_read,
403};
404
405static void __attr_init(struct gator_attr *const attr)
406{
407 attr->name[0] = '\0';
408 attr->enabled = 0;
409 attr->type = 0;
410 attr->event = 0;
411 attr->count = 0;
412 attr->key = gator_events_get_key();
413}
414
415#ifdef CONFIG_OF
416
417static const struct of_device_id arm_cci_matches[] = {
418 {.compatible = "arm,cci-400" },
419 {},
420};
421
422static int probe_cci_revision(void)
423{
424 struct device_node *np;
425 struct resource res;
426 void __iomem *cci_ctrl_base;
427 int rev;
428 int ret = DEFAULT_CCI_REVISION;
429
430 np = of_find_matching_node(NULL, arm_cci_matches);
431 if (!np) {
432 return ret;
433 }
434
435 if (of_address_to_resource(np, 0, &res)) {
436 goto node_put;
437 }
438
439 cci_ctrl_base = ioremap(res.start, resource_size(&res));
440
441 rev = (readl_relaxed(cci_ctrl_base + 0xfe8) >> 4) & 0xf;
442
443 if (rev <= 4) {
444 ret = 0;
445 } else if (rev <= 6) {
446 ret = 1;
447 }
448
449 iounmap(cci_ctrl_base);
450
451 node_put:
452 of_node_put(np);
453
454 return ret;
455}
456
457#else
458
459static int probe_cci_revision(void)
460{
461 return DEFAULT_CCI_REVISION;
462}
463
464#endif
465
466static void gator_events_perf_pmu_cci_init(const int type)
467{
468 int cnt;
469 const char *cci_name;
470
471 switch (probe_cci_revision()) {
472 case 0:
473 cci_name = "CCI_400";
474 break;
475 case 1:
476 cci_name = "CCI_400-r1";
477 break;
478 default:
479 pr_debug("gator: unrecognized cci-400 revision\n");
480 return;
481 }
482
483 snprintf(uc_attrs[uc_attr_count].name, sizeof(uc_attrs[uc_attr_count].name), "%s_ccnt", cci_name);
484 uc_attrs[uc_attr_count].type = type;
485 ++uc_attr_count;
486
487 for (cnt = 0; cnt < CCI_400; ++cnt, ++uc_attr_count) {
488 struct gator_attr *const attr = &uc_attrs[uc_attr_count];
489 snprintf(attr->name, sizeof(attr->name), "%s_cnt%d", cci_name, cnt);
490 attr->type = type;
491 }
492}
493
494static void gator_events_perf_pmu_cpu_init(const struct gator_cpu *const gator_cpu, const int type)
495{
496 int cnt;
497
498 snprintf(attrs[attr_count].name, sizeof(attrs[attr_count].name), "%s_ccnt", gator_cpu->pmnc_name);
499 attrs[attr_count].type = type;
500 ++attr_count;
501
502 for (cnt = 0; cnt < gator_cpu->pmnc_counters; ++cnt, ++attr_count) {
503 struct gator_attr *const attr = &attrs[attr_count];
504 snprintf(attr->name, sizeof(attr->name), "%s_cnt%d", gator_cpu->pmnc_name, cnt);
505 attr->type = type;
506 }
507}
508
509int gator_events_perf_pmu_init(void)
510{
511 struct perf_event_attr pea;
512 struct perf_event *pe;
513 const struct gator_cpu *gator_cpu;
514 int type;
515 int cpu;
516 int cnt;
517 bool found_cpu = false;
518
519 for (cnt = 0; cnt < CNTMAX; cnt++) {
520 __attr_init(&attrs[cnt]);
521 }
522 for (cnt = 0; cnt < UCCNT; cnt++) {
523 __attr_init(&uc_attrs[cnt]);
524 }
525
526 memset(&pea, 0, sizeof(pea));
527 pea.size = sizeof(pea);
528 pea.config = 0xFF;
529 attr_count = 0;
530 uc_attr_count = 0;
531 for (type = PERF_TYPE_MAX; type < 0x20; ++type) {
532 pea.type = type;
533
534 // A particular PMU may work on some but not all cores, so try on each core
535 pe = NULL;
536 for_each_present_cpu(cpu) {
537#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)
538 pe = perf_event_create_kernel_counter(&pea, cpu, 0, dummy_handler);
539#else
540 pe = perf_event_create_kernel_counter(&pea, cpu, 0, dummy_handler, 0);
541#endif
542 if (!IS_ERR(pe)) {
543 break;
544 }
545 }
546 // Assume that valid PMUs are contiguous
547 if (IS_ERR(pe)) {
548 break;
549 }
550
551 if (pe->pmu != NULL && type == pe->pmu->type) {
552 if (strcmp("CCI", pe->pmu->name) == 0 || strcmp("CCI_400", pe->pmu->name) == 0 || strcmp("CCI_400-r1", pe->pmu->name) == 0) {
553 gator_events_perf_pmu_cci_init(type);
554 } else if ((gator_cpu = gator_find_cpu_by_pmu_name(pe->pmu->name)) != NULL) {
555 found_cpu = true;
556 gator_events_perf_pmu_cpu_init(gator_cpu, type);
557 }
558 // Initialize gator_attrs for dynamic PMUs here
559 }
560
561 perf_event_release_kernel(pe);
562 }
563
564 if (!found_cpu) {
565 const struct gator_cpu *const gator_cpu = gator_find_cpu_by_cpuid(gator_cpuid());
566 if (gator_cpu == NULL) {
567 return -1;
568 }
569 gator_events_perf_pmu_cpu_init(gator_cpu, PERF_TYPE_RAW);
570 }
571
572 // Initialize gator_attrs for non-dynamic PMUs here
573
574 if (attr_count > CNTMAX) {
575 printk(KERN_ERR "gator: Too many perf counters\n");
576 return -1;
577 }
578
579 if (uc_attr_count > UCCNT) {
580 printk(KERN_ERR "gator: Too many perf uncore counters\n");
581 return -1;
582 }
583
584 return gator_events_install(&gator_events_perf_pmu_interface);
585}
586
587#endif
diff --git a/drivers/gator/gator_events_sched.c b/drivers/gator/gator_events_sched.c
new file mode 100644
index 00000000000..9e391583018
--- /dev/null
+++ b/drivers/gator/gator_events_sched.c
@@ -0,0 +1,113 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10#include "gator.h"
11#include <trace/events/sched.h>
12
13#define SCHED_SWITCH 0
14#define SCHED_TOTAL (SCHED_SWITCH+1)
15
16static ulong sched_switch_enabled;
17static ulong sched_switch_key;
18static DEFINE_PER_CPU(int[SCHED_TOTAL], schedCnt);
19static DEFINE_PER_CPU(int[SCHED_TOTAL * 2], schedGet);
20
21#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
22GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct rq *rq, struct task_struct *prev, struct task_struct *next))
23#else
24GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct task_struct *prev, struct task_struct *next))
25#endif
26{
27 unsigned long flags;
28
29 // disable interrupts to synchronize with gator_events_sched_read()
30 // spinlocks not needed since percpu buffers are used
31 local_irq_save(flags);
32 per_cpu(schedCnt, get_physical_cpu())[SCHED_SWITCH]++;
33 local_irq_restore(flags);
34}
35
36static int gator_events_sched_create_files(struct super_block *sb, struct dentry *root)
37{
38 struct dentry *dir;
39
40 /* switch */
41 dir = gatorfs_mkdir(sb, root, "Linux_sched_switch");
42 if (!dir) {
43 return -1;
44 }
45 gatorfs_create_ulong(sb, dir, "enabled", &sched_switch_enabled);
46 gatorfs_create_ro_ulong(sb, dir, "key", &sched_switch_key);
47
48 return 0;
49}
50
51static int gator_events_sched_start(void)
52{
53 // register tracepoints
54 if (sched_switch_enabled)
55 if (GATOR_REGISTER_TRACE(sched_switch))
56 goto sched_switch_exit;
57 pr_debug("gator: registered scheduler event tracepoints\n");
58
59 return 0;
60
61 // unregister tracepoints on error
62sched_switch_exit:
63 pr_err("gator: scheduler event tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n");
64
65 return -1;
66}
67
68static void gator_events_sched_stop(void)
69{
70 if (sched_switch_enabled)
71 GATOR_UNREGISTER_TRACE(sched_switch);
72 pr_debug("gator: unregistered scheduler event tracepoints\n");
73
74 sched_switch_enabled = 0;
75}
76
77static int gator_events_sched_read(int **buffer)
78{
79 unsigned long flags;
80 int len, value;
81 int cpu = get_physical_cpu();
82
83 len = 0;
84 if (sched_switch_enabled) {
85 local_irq_save(flags);
86 value = per_cpu(schedCnt, cpu)[SCHED_SWITCH];
87 per_cpu(schedCnt, cpu)[SCHED_SWITCH] = 0;
88 local_irq_restore(flags);
89 per_cpu(schedGet, cpu)[len++] = sched_switch_key;
90 per_cpu(schedGet, cpu)[len++] = value;
91 }
92
93 if (buffer)
94 *buffer = per_cpu(schedGet, cpu);
95
96 return len;
97}
98
99static struct gator_interface gator_events_sched_interface = {
100 .create_files = gator_events_sched_create_files,
101 .start = gator_events_sched_start,
102 .stop = gator_events_sched_stop,
103 .read = gator_events_sched_read,
104};
105
106int gator_events_sched_init(void)
107{
108 sched_switch_enabled = 0;
109
110 sched_switch_key = gator_events_get_key();
111
112 return gator_events_install(&gator_events_sched_interface);
113}
diff --git a/drivers/gator/gator_events_scorpion.c b/drivers/gator/gator_events_scorpion.c
new file mode 100644
index 00000000000..2e5be8d50e9
--- /dev/null
+++ b/drivers/gator/gator_events_scorpion.c
@@ -0,0 +1,669 @@
1/**
2 * Copyright (C) ARM Limited 2011-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "gator.h"
10
11// gator_events_perf_pmu.c is used if perf is supported
12#if GATOR_NO_PERF_SUPPORT
13
14static const char *pmnc_name;
15static int pmnc_counters;
16
17// Per-CPU PMNC: config reg
18#define PMNC_E (1 << 0) /* Enable all counters */
19#define PMNC_P (1 << 1) /* Reset all counters */
20#define PMNC_C (1 << 2) /* Cycle counter reset */
21#define PMNC_D (1 << 3) /* CCNT counts every 64th cpu cycle */
22#define PMNC_X (1 << 4) /* Export to ETM */
23#define PMNC_DP (1 << 5) /* Disable CCNT if non-invasive debug */
24#define PMNC_MASK 0x3f /* Mask for writable bits */
25
26// ccnt reg
27#define CCNT_REG (1 << 31)
28
29#define CCNT 0
30#define CNT0 1
31#define CNTMAX (4+1)
32
33static unsigned long pmnc_enabled[CNTMAX];
34static unsigned long pmnc_event[CNTMAX];
35static unsigned long pmnc_key[CNTMAX];
36
37static DEFINE_PER_CPU(int[CNTMAX * 2], perfCnt);
38
39enum scorpion_perf_types {
40 SCORPION_ICACHE_EXPL_INV = 0x4c,
41 SCORPION_ICACHE_MISS = 0x4d,
42 SCORPION_ICACHE_ACCESS = 0x4e,
43 SCORPION_ICACHE_CACHEREQ_L2 = 0x4f,
44 SCORPION_ICACHE_NOCACHE_L2 = 0x50,
45 SCORPION_HIQUP_NOPED = 0x51,
46 SCORPION_DATA_ABORT = 0x52,
47 SCORPION_IRQ = 0x53,
48 SCORPION_FIQ = 0x54,
49 SCORPION_ALL_EXCPT = 0x55,
50 SCORPION_UNDEF = 0x56,
51 SCORPION_SVC = 0x57,
52 SCORPION_SMC = 0x58,
53 SCORPION_PREFETCH_ABORT = 0x59,
54 SCORPION_INDEX_CHECK = 0x5a,
55 SCORPION_NULL_CHECK = 0x5b,
56 SCORPION_EXPL_ICIALLU = 0x5c,
57 SCORPION_IMPL_ICIALLU = 0x5d,
58 SCORPION_NONICIALLU_BTAC_INV = 0x5e,
59 SCORPION_ICIMVAU_IMPL_ICIALLU = 0x5f,
60 SCORPION_SPIPE_ONLY_CYCLES = 0x60,
61 SCORPION_XPIPE_ONLY_CYCLES = 0x61,
62 SCORPION_DUAL_CYCLES = 0x62,
63 SCORPION_DISPATCH_ANY_CYCLES = 0x63,
64 SCORPION_FIFO_FULLBLK_CMT = 0x64,
65 SCORPION_FAIL_COND_INST = 0x65,
66 SCORPION_PASS_COND_INST = 0x66,
67 SCORPION_ALLOW_VU_CLK = 0x67,
68 SCORPION_VU_IDLE = 0x68,
69 SCORPION_ALLOW_L2_CLK = 0x69,
70 SCORPION_L2_IDLE = 0x6a,
71 SCORPION_DTLB_IMPL_INV_SCTLR_DACR = 0x6b,
72 SCORPION_DTLB_EXPL_INV = 0x6c,
73 SCORPION_DTLB_MISS = 0x6d,
74 SCORPION_DTLB_ACCESS = 0x6e,
75 SCORPION_ITLB_MISS = 0x6f,
76 SCORPION_ITLB_IMPL_INV = 0x70,
77 SCORPION_ITLB_EXPL_INV = 0x71,
78 SCORPION_UTLB_D_MISS = 0x72,
79 SCORPION_UTLB_D_ACCESS = 0x73,
80 SCORPION_UTLB_I_MISS = 0x74,
81 SCORPION_UTLB_I_ACCESS = 0x75,
82 SCORPION_UTLB_INV_ASID = 0x76,
83 SCORPION_UTLB_INV_MVA = 0x77,
84 SCORPION_UTLB_INV_ALL = 0x78,
85 SCORPION_S2_HOLD_RDQ_UNAVAIL = 0x79,
86 SCORPION_S2_HOLD = 0x7a,
87 SCORPION_S2_HOLD_DEV_OP = 0x7b,
88 SCORPION_S2_HOLD_ORDER = 0x7c,
89 SCORPION_S2_HOLD_BARRIER = 0x7d,
90 SCORPION_VIU_DUAL_CYCLE = 0x7e,
91 SCORPION_VIU_SINGLE_CYCLE = 0x7f,
92 SCORPION_VX_PIPE_WAR_STALL_CYCLES = 0x80,
93 SCORPION_VX_PIPE_WAW_STALL_CYCLES = 0x81,
94 SCORPION_VX_PIPE_RAW_STALL_CYCLES = 0x82,
95 SCORPION_VX_PIPE_LOAD_USE_STALL = 0x83,
96 SCORPION_VS_PIPE_WAR_STALL_CYCLES = 0x84,
97 SCORPION_VS_PIPE_WAW_STALL_CYCLES = 0x85,
98 SCORPION_VS_PIPE_RAW_STALL_CYCLES = 0x86,
99 SCORPION_EXCEPTIONS_INV_OPERATION = 0x87,
100 SCORPION_EXCEPTIONS_DIV_BY_ZERO = 0x88,
101 SCORPION_COND_INST_FAIL_VX_PIPE = 0x89,
102 SCORPION_COND_INST_FAIL_VS_PIPE = 0x8a,
103 SCORPION_EXCEPTIONS_OVERFLOW = 0x8b,
104 SCORPION_EXCEPTIONS_UNDERFLOW = 0x8c,
105 SCORPION_EXCEPTIONS_DENORM = 0x8d,
106#ifdef CONFIG_ARCH_MSM_SCORPIONMP
107 SCORPIONMP_NUM_BARRIERS = 0x8e,
108 SCORPIONMP_BARRIER_CYCLES = 0x8f,
109#else
110 SCORPION_BANK_AB_HIT = 0x8e,
111 SCORPION_BANK_AB_ACCESS = 0x8f,
112 SCORPION_BANK_CD_HIT = 0x90,
113 SCORPION_BANK_CD_ACCESS = 0x91,
114 SCORPION_BANK_AB_DSIDE_HIT = 0x92,
115 SCORPION_BANK_AB_DSIDE_ACCESS = 0x93,
116 SCORPION_BANK_CD_DSIDE_HIT = 0x94,
117 SCORPION_BANK_CD_DSIDE_ACCESS = 0x95,
118 SCORPION_BANK_AB_ISIDE_HIT = 0x96,
119 SCORPION_BANK_AB_ISIDE_ACCESS = 0x97,
120 SCORPION_BANK_CD_ISIDE_HIT = 0x98,
121 SCORPION_BANK_CD_ISIDE_ACCESS = 0x99,
122 SCORPION_ISIDE_RD_WAIT = 0x9a,
123 SCORPION_DSIDE_RD_WAIT = 0x9b,
124 SCORPION_BANK_BYPASS_WRITE = 0x9c,
125 SCORPION_BANK_AB_NON_CASTOUT = 0x9d,
126 SCORPION_BANK_AB_L2_CASTOUT = 0x9e,
127 SCORPION_BANK_CD_NON_CASTOUT = 0x9f,
128 SCORPION_BANK_CD_L2_CASTOUT = 0xa0,
129#endif
130 MSM_MAX_EVT
131};
132
133struct scorp_evt {
134 u32 evt_type;
135 u32 val;
136 u8 grp;
137 u32 evt_type_act;
138};
139
140static const struct scorp_evt sc_evt[] = {
141 {SCORPION_ICACHE_EXPL_INV, 0x80000500, 0, 0x4d},
142 {SCORPION_ICACHE_MISS, 0x80050000, 0, 0x4e},
143 {SCORPION_ICACHE_ACCESS, 0x85000000, 0, 0x4f},
144 {SCORPION_ICACHE_CACHEREQ_L2, 0x86000000, 0, 0x4f},
145 {SCORPION_ICACHE_NOCACHE_L2, 0x87000000, 0, 0x4f},
146 {SCORPION_HIQUP_NOPED, 0x80080000, 0, 0x4e},
147 {SCORPION_DATA_ABORT, 0x8000000a, 0, 0x4c},
148 {SCORPION_IRQ, 0x80000a00, 0, 0x4d},
149 {SCORPION_FIQ, 0x800a0000, 0, 0x4e},
150 {SCORPION_ALL_EXCPT, 0x8a000000, 0, 0x4f},
151 {SCORPION_UNDEF, 0x8000000b, 0, 0x4c},
152 {SCORPION_SVC, 0x80000b00, 0, 0x4d},
153 {SCORPION_SMC, 0x800b0000, 0, 0x4e},
154 {SCORPION_PREFETCH_ABORT, 0x8b000000, 0, 0x4f},
155 {SCORPION_INDEX_CHECK, 0x8000000c, 0, 0x4c},
156 {SCORPION_NULL_CHECK, 0x80000c00, 0, 0x4d},
157 {SCORPION_EXPL_ICIALLU, 0x8000000d, 0, 0x4c},
158 {SCORPION_IMPL_ICIALLU, 0x80000d00, 0, 0x4d},
159 {SCORPION_NONICIALLU_BTAC_INV, 0x800d0000, 0, 0x4e},
160 {SCORPION_ICIMVAU_IMPL_ICIALLU, 0x8d000000, 0, 0x4f},
161
162 {SCORPION_SPIPE_ONLY_CYCLES, 0x80000600, 1, 0x51},
163 {SCORPION_XPIPE_ONLY_CYCLES, 0x80060000, 1, 0x52},
164 {SCORPION_DUAL_CYCLES, 0x86000000, 1, 0x53},
165 {SCORPION_DISPATCH_ANY_CYCLES, 0x89000000, 1, 0x53},
166 {SCORPION_FIFO_FULLBLK_CMT, 0x8000000d, 1, 0x50},
167 {SCORPION_FAIL_COND_INST, 0x800d0000, 1, 0x52},
168 {SCORPION_PASS_COND_INST, 0x8d000000, 1, 0x53},
169 {SCORPION_ALLOW_VU_CLK, 0x8000000e, 1, 0x50},
170 {SCORPION_VU_IDLE, 0x80000e00, 1, 0x51},
171 {SCORPION_ALLOW_L2_CLK, 0x800e0000, 1, 0x52},
172 {SCORPION_L2_IDLE, 0x8e000000, 1, 0x53},
173
174 {SCORPION_DTLB_IMPL_INV_SCTLR_DACR, 0x80000001, 2, 0x54},
175 {SCORPION_DTLB_EXPL_INV, 0x80000100, 2, 0x55},
176 {SCORPION_DTLB_MISS, 0x80010000, 2, 0x56},
177 {SCORPION_DTLB_ACCESS, 0x81000000, 2, 0x57},
178 {SCORPION_ITLB_MISS, 0x80000200, 2, 0x55},
179 {SCORPION_ITLB_IMPL_INV, 0x80020000, 2, 0x56},
180 {SCORPION_ITLB_EXPL_INV, 0x82000000, 2, 0x57},
181 {SCORPION_UTLB_D_MISS, 0x80000003, 2, 0x54},
182 {SCORPION_UTLB_D_ACCESS, 0x80000300, 2, 0x55},
183 {SCORPION_UTLB_I_MISS, 0x80030000, 2, 0x56},
184 {SCORPION_UTLB_I_ACCESS, 0x83000000, 2, 0x57},
185 {SCORPION_UTLB_INV_ASID, 0x80000400, 2, 0x55},
186 {SCORPION_UTLB_INV_MVA, 0x80040000, 2, 0x56},
187 {SCORPION_UTLB_INV_ALL, 0x84000000, 2, 0x57},
188 {SCORPION_S2_HOLD_RDQ_UNAVAIL, 0x80000800, 2, 0x55},
189 {SCORPION_S2_HOLD, 0x88000000, 2, 0x57},
190 {SCORPION_S2_HOLD_DEV_OP, 0x80000900, 2, 0x55},
191 {SCORPION_S2_HOLD_ORDER, 0x80090000, 2, 0x56},
192 {SCORPION_S2_HOLD_BARRIER, 0x89000000, 2, 0x57},
193
194 {SCORPION_VIU_DUAL_CYCLE, 0x80000001, 4, 0x5c},
195 {SCORPION_VIU_SINGLE_CYCLE, 0x80000100, 4, 0x5d},
196 {SCORPION_VX_PIPE_WAR_STALL_CYCLES, 0x80000005, 4, 0x5c},
197 {SCORPION_VX_PIPE_WAW_STALL_CYCLES, 0x80000500, 4, 0x5d},
198 {SCORPION_VX_PIPE_RAW_STALL_CYCLES, 0x80050000, 4, 0x5e},
199 {SCORPION_VX_PIPE_LOAD_USE_STALL, 0x80000007, 4, 0x5c},
200 {SCORPION_VS_PIPE_WAR_STALL_CYCLES, 0x80000008, 4, 0x5c},
201 {SCORPION_VS_PIPE_WAW_STALL_CYCLES, 0x80000800, 4, 0x5d},
202 {SCORPION_VS_PIPE_RAW_STALL_CYCLES, 0x80080000, 4, 0x5e},
203 {SCORPION_EXCEPTIONS_INV_OPERATION, 0x8000000b, 4, 0x5c},
204 {SCORPION_EXCEPTIONS_DIV_BY_ZERO, 0x80000b00, 4, 0x5d},
205 {SCORPION_COND_INST_FAIL_VX_PIPE, 0x800b0000, 4, 0x5e},
206 {SCORPION_COND_INST_FAIL_VS_PIPE, 0x8b000000, 4, 0x5f},
207 {SCORPION_EXCEPTIONS_OVERFLOW, 0x8000000c, 4, 0x5c},
208 {SCORPION_EXCEPTIONS_UNDERFLOW, 0x80000c00, 4, 0x5d},
209 {SCORPION_EXCEPTIONS_DENORM, 0x8c000000, 4, 0x5f},
210
211#ifdef CONFIG_ARCH_MSM_SCORPIONMP
212 {SCORPIONMP_NUM_BARRIERS, 0x80000e00, 3, 0x59},
213 {SCORPIONMP_BARRIER_CYCLES, 0x800e0000, 3, 0x5a},
214#else
215 {SCORPION_BANK_AB_HIT, 0x80000001, 3, 0x58},
216 {SCORPION_BANK_AB_ACCESS, 0x80000100, 3, 0x59},
217 {SCORPION_BANK_CD_HIT, 0x80010000, 3, 0x5a},
218 {SCORPION_BANK_CD_ACCESS, 0x81000000, 3, 0x5b},
219 {SCORPION_BANK_AB_DSIDE_HIT, 0x80000002, 3, 0x58},
220 {SCORPION_BANK_AB_DSIDE_ACCESS, 0x80000200, 3, 0x59},
221 {SCORPION_BANK_CD_DSIDE_HIT, 0x80020000, 3, 0x5a},
222 {SCORPION_BANK_CD_DSIDE_ACCESS, 0x82000000, 3, 0x5b},
223 {SCORPION_BANK_AB_ISIDE_HIT, 0x80000003, 3, 0x58},
224 {SCORPION_BANK_AB_ISIDE_ACCESS, 0x80000300, 3, 0x59},
225 {SCORPION_BANK_CD_ISIDE_HIT, 0x80030000, 3, 0x5a},
226 {SCORPION_BANK_CD_ISIDE_ACCESS, 0x83000000, 3, 0x5b},
227 {SCORPION_ISIDE_RD_WAIT, 0x80000009, 3, 0x58},
228 {SCORPION_DSIDE_RD_WAIT, 0x80090000, 3, 0x5a},
229 {SCORPION_BANK_BYPASS_WRITE, 0x8000000a, 3, 0x58},
230 {SCORPION_BANK_AB_NON_CASTOUT, 0x8000000c, 3, 0x58},
231 {SCORPION_BANK_AB_L2_CASTOUT, 0x80000c00, 3, 0x59},
232 {SCORPION_BANK_CD_NON_CASTOUT, 0x800c0000, 3, 0x5a},
233 {SCORPION_BANK_CD_L2_CASTOUT, 0x8c000000, 3, 0x5b},
234#endif
235};
236
237static inline void scorpion_pmnc_write(u32 val)
238{
239 val &= PMNC_MASK;
240 asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r" (val));
241}
242
243static inline u32 scorpion_pmnc_read(void)
244{
245 u32 val;
246 asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val));
247 return val;
248}
249
250static inline u32 scorpion_ccnt_read(void)
251{
252 u32 val;
253 asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val));
254 return val;
255}
256
257static inline u32 scorpion_cntn_read(void)
258{
259 u32 val;
260 asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val));
261 return val;
262}
263
264static inline u32 scorpion_pmnc_enable_counter(unsigned int cnt)
265{
266 u32 val;
267
268 if (cnt >= CNTMAX) {
269 pr_err("gator: CPU%u enabling wrong PMNC counter %d\n", smp_processor_id(), cnt);
270 return -1;
271 }
272
273 if (cnt == CCNT)
274 val = CCNT_REG;
275 else
276 val = (1 << (cnt - CNT0));
277
278 asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val));
279
280 return cnt;
281}
282
283static inline u32 scorpion_pmnc_disable_counter(unsigned int cnt)
284{
285 u32 val;
286
287 if (cnt >= CNTMAX) {
288 pr_err("gator: CPU%u disabling wrong PMNC counter %d\n", smp_processor_id(), cnt);
289 return -1;
290 }
291
292 if (cnt == CCNT)
293 val = CCNT_REG;
294 else
295 val = (1 << (cnt - CNT0));
296
297 asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val));
298
299 return cnt;
300}
301
302static inline int scorpion_pmnc_select_counter(unsigned int cnt)
303{
304 u32 val;
305
306 if ((cnt == CCNT) || (cnt >= CNTMAX)) {
307 pr_err("gator: CPU%u selecting wrong PMNC counter %d\n", smp_processor_id(), cnt);
308 return -1;
309 }
310
311 val = (cnt - CNT0);
312 asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val));
313
314 return cnt;
315}
316
317static u32 scorpion_read_lpm0(void)
318{
319 u32 val;
320 asm volatile("mrc p15, 0, %0, c15, c0, 0" : "=r" (val));
321 return val;
322}
323
324static void scorpion_write_lpm0(u32 val)
325{
326 asm volatile("mcr p15, 0, %0, c15, c0, 0" : : "r" (val));
327}
328
329static u32 scorpion_read_lpm1(void)
330{
331 u32 val;
332 asm volatile("mrc p15, 1, %0, c15, c0, 0" : "=r" (val));
333 return val;
334}
335
336static void scorpion_write_lpm1(u32 val)
337{
338 asm volatile("mcr p15, 1, %0, c15, c0, 0" : : "r" (val));
339}
340
341static u32 scorpion_read_lpm2(void)
342{
343 u32 val;
344 asm volatile("mrc p15, 2, %0, c15, c0, 0" : "=r" (val));
345 return val;
346}
347
348static void scorpion_write_lpm2(u32 val)
349{
350 asm volatile("mcr p15, 2, %0, c15, c0, 0" : : "r" (val));
351}
352
353static u32 scorpion_read_l2lpm(void)
354{
355 u32 val;
356 asm volatile("mrc p15, 3, %0, c15, c2, 0" : "=r" (val));
357 return val;
358}
359
360static void scorpion_write_l2lpm(u32 val)
361{
362 asm volatile("mcr p15, 3, %0, c15, c2, 0" : : "r" (val));
363}
364
365static u32 scorpion_read_vlpm(void)
366{
367 u32 val;
368 asm volatile("mrc p10, 7, %0, c11, c0, 0" : "=r" (val));
369 return val;
370}
371
372static void scorpion_write_vlpm(u32 val)
373{
374 asm volatile("mcr p10, 7, %0, c11, c0, 0" : : "r" (val));
375}
376
377struct scorpion_access_funcs {
378 u32(*read)(void);
379 void (*write)(u32);
380};
381
382struct scorpion_access_funcs scor_func[] = {
383 {scorpion_read_lpm0, scorpion_write_lpm0},
384 {scorpion_read_lpm1, scorpion_write_lpm1},
385 {scorpion_read_lpm2, scorpion_write_lpm2},
386 {scorpion_read_l2lpm, scorpion_write_l2lpm},
387 {scorpion_read_vlpm, scorpion_write_vlpm},
388};
389
390u32 venum_orig_val;
391u32 fp_orig_val;
392
393static void scorpion_pre_vlpm(void)
394{
395 u32 venum_new_val;
396 u32 fp_new_val;
397
398 /* CPACR Enable CP10 access */
399 asm volatile("mrc p15, 0, %0, c1, c0, 2" : "=r" (venum_orig_val));
400 venum_new_val = venum_orig_val | 0x00300000;
401 asm volatile("mcr p15, 0, %0, c1, c0, 2" : : "r" (venum_new_val));
402 /* Enable FPEXC */
403 asm volatile("mrc p10, 7, %0, c8, c0, 0" : "=r" (fp_orig_val));
404 fp_new_val = fp_orig_val | 0x40000000;
405 asm volatile("mcr p10, 7, %0, c8, c0, 0" : : "r" (fp_new_val));
406}
407
408static void scorpion_post_vlpm(void)
409{
410 /* Restore FPEXC */
411 asm volatile("mcr p10, 7, %0, c8, c0, 0" : : "r" (fp_orig_val));
412 /* Restore CPACR */
413 asm volatile("mcr p15, 0, %0, c1, c0, 2" : : "r" (venum_orig_val));
414}
415
416#define COLMN0MASK 0x000000ff
417#define COLMN1MASK 0x0000ff00
418#define COLMN2MASK 0x00ff0000
419static u32 scorpion_get_columnmask(u32 setval)
420{
421 if (setval & COLMN0MASK)
422 return 0xffffff00;
423 else if (setval & COLMN1MASK)
424 return 0xffff00ff;
425 else if (setval & COLMN2MASK)
426 return 0xff00ffff;
427 else
428 return 0x80ffffff;
429}
430
431static void scorpion_evt_setup(u32 gr, u32 setval)
432{
433 u32 val;
434 if (gr == 4)
435 scorpion_pre_vlpm();
436 val = scorpion_get_columnmask(setval) & scor_func[gr].read();
437 val = val | setval;
438 scor_func[gr].write(val);
439 if (gr == 4)
440 scorpion_post_vlpm();
441}
442
443static int get_scorpion_evtinfo(unsigned int evt_type, struct scorp_evt *evtinfo)
444{
445 u32 idx;
446 if ((evt_type < 0x4c) || (evt_type >= MSM_MAX_EVT))
447 return 0;
448 idx = evt_type - 0x4c;
449 if (sc_evt[idx].evt_type == evt_type) {
450 evtinfo->val = sc_evt[idx].val;
451 evtinfo->grp = sc_evt[idx].grp;
452 evtinfo->evt_type_act = sc_evt[idx].evt_type_act;
453 return 1;
454 }
455 return 0;
456}
457
458static inline void scorpion_pmnc_write_evtsel(unsigned int cnt, u32 val)
459{
460 if (scorpion_pmnc_select_counter(cnt) == cnt) {
461 if (val < 0x40) {
462 asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val));
463 } else {
464 u32 zero = 0;
465 struct scorp_evt evtinfo;
466 // extract evtinfo.grp and evtinfo.tevt_type_act from val
467 if (get_scorpion_evtinfo(val, &evtinfo) == 0)
468 return;
469 asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (evtinfo.evt_type_act));
470 asm volatile("mcr p15, 0, %0, c9, c15, 0" : : "r" (zero));
471 scorpion_evt_setup(evtinfo.grp, val);
472 }
473 }
474}
475
476static void scorpion_pmnc_reset_counter(unsigned int cnt)
477{
478 u32 val = 0;
479
480 if (cnt == CCNT) {
481 scorpion_pmnc_disable_counter(cnt);
482
483 asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (val));
484
485 if (pmnc_enabled[cnt] != 0)
486 scorpion_pmnc_enable_counter(cnt);
487
488 } else if (cnt >= CNTMAX) {
489 pr_err("gator: CPU%u resetting wrong PMNC counter %d\n", smp_processor_id(), cnt);
490 } else {
491 scorpion_pmnc_disable_counter(cnt);
492
493 if (scorpion_pmnc_select_counter(cnt) == cnt)
494 asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (val));
495
496 if (pmnc_enabled[cnt] != 0)
497 scorpion_pmnc_enable_counter(cnt);
498 }
499}
500
501static int gator_events_scorpion_create_files(struct super_block *sb, struct dentry *root)
502{
503 struct dentry *dir;
504 int i;
505
506 for (i = 0; i < pmnc_counters; i++) {
507 char buf[40];
508 if (i == 0) {
509 snprintf(buf, sizeof buf, "%s_ccnt", pmnc_name);
510 } else {
511 snprintf(buf, sizeof buf, "%s_cnt%d", pmnc_name, i - 1);
512 }
513 dir = gatorfs_mkdir(sb, root, buf);
514 if (!dir) {
515 return -1;
516 }
517 gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]);
518 gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]);
519 if (i > 0) {
520 gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]);
521 }
522 }
523
524 return 0;
525}
526
527static int gator_events_scorpion_online(int **buffer, bool migrate)
528{
529 unsigned int cnt, len = 0, cpu = smp_processor_id();
530
531 if (scorpion_pmnc_read() & PMNC_E) {
532 scorpion_pmnc_write(scorpion_pmnc_read() & ~PMNC_E);
533 }
534
535 /* Initialize & Reset PMNC: C bit and P bit */
536 scorpion_pmnc_write(PMNC_P | PMNC_C);
537
538 for (cnt = CCNT; cnt < CNTMAX; cnt++) {
539 unsigned long event;
540
541 if (!pmnc_enabled[cnt])
542 continue;
543
544 // disable counter
545 scorpion_pmnc_disable_counter(cnt);
546
547 event = pmnc_event[cnt] & 255;
548
549 // Set event (if destined for PMNx counters), We don't need to set the event if it's a cycle count
550 if (cnt != CCNT)
551 scorpion_pmnc_write_evtsel(cnt, event);
552
553 // reset counter
554 scorpion_pmnc_reset_counter(cnt);
555
556 // Enable counter, do not enable interrupt for this counter
557 scorpion_pmnc_enable_counter(cnt);
558 }
559
560 // enable
561 scorpion_pmnc_write(scorpion_pmnc_read() | PMNC_E);
562
563 // read the counters and toss the invalid data, return zero instead
564 for (cnt = 0; cnt < pmnc_counters; cnt++) {
565 if (pmnc_enabled[cnt]) {
566 if (cnt == CCNT) {
567 scorpion_ccnt_read();
568 } else if (scorpion_pmnc_select_counter(cnt) == cnt) {
569 scorpion_cntn_read();
570 }
571 scorpion_pmnc_reset_counter(cnt);
572
573 per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
574 per_cpu(perfCnt, cpu)[len++] = 0;
575 }
576 }
577
578 if (buffer)
579 *buffer = per_cpu(perfCnt, cpu);
580
581 return len;
582}
583
584static int gator_events_scorpion_offline(int **buffer, bool migrate)
585{
586 scorpion_pmnc_write(scorpion_pmnc_read() & ~PMNC_E);
587 return 0;
588}
589
590static void gator_events_scorpion_stop(void)
591{
592 unsigned int cnt;
593
594 for (cnt = CCNT; cnt < CNTMAX; cnt++) {
595 pmnc_enabled[cnt] = 0;
596 pmnc_event[cnt] = 0;
597 }
598}
599
600static int gator_events_scorpion_read(int **buffer)
601{
602 int cnt, len = 0;
603 int cpu = smp_processor_id();
604
605 // a context switch may occur before the online hotplug event, thus need to check that the pmu is enabled
606 if (!(scorpion_pmnc_read() & PMNC_E)) {
607 return 0;
608 }
609
610 for (cnt = 0; cnt < pmnc_counters; cnt++) {
611 if (pmnc_enabled[cnt]) {
612 int value;
613 if (cnt == CCNT) {
614 value = scorpion_ccnt_read();
615 } else if (scorpion_pmnc_select_counter(cnt) == cnt) {
616 value = scorpion_cntn_read();
617 } else {
618 value = 0;
619 }
620 scorpion_pmnc_reset_counter(cnt);
621
622 per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
623 per_cpu(perfCnt, cpu)[len++] = value;
624 }
625 }
626
627 if (buffer)
628 *buffer = per_cpu(perfCnt, cpu);
629
630 return len;
631}
632
633static struct gator_interface gator_events_scorpion_interface = {
634 .create_files = gator_events_scorpion_create_files,
635 .stop = gator_events_scorpion_stop,
636 .online = gator_events_scorpion_online,
637 .offline = gator_events_scorpion_offline,
638 .read = gator_events_scorpion_read,
639};
640
641int gator_events_scorpion_init(void)
642{
643 unsigned int cnt;
644
645 switch (gator_cpuid()) {
646 case SCORPION:
647 pmnc_name = "Scorpion";
648 pmnc_counters = 4;
649 break;
650 case SCORPIONMP:
651 pmnc_name = "ScorpionMP";
652 pmnc_counters = 4;
653 break;
654 default:
655 return -1;
656 }
657
658 pmnc_counters++; // CNT[n] + CCNT
659
660 for (cnt = CCNT; cnt < CNTMAX; cnt++) {
661 pmnc_enabled[cnt] = 0;
662 pmnc_event[cnt] = 0;
663 pmnc_key[cnt] = gator_events_get_key();
664 }
665
666 return gator_events_install(&gator_events_scorpion_interface);
667}
668
669#endif
diff --git a/drivers/gator/gator_events_threads.c b/drivers/gator/gator_events_threads.c
new file mode 100644
index 00000000000..9de85862fe6
--- /dev/null
+++ b/drivers/gator/gator_events_threads.c
@@ -0,0 +1,115 @@
1/*
2 * Sample activity provider
3 *
4 * Copyright (C) ARM Limited 2014. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * See gator_events_mmapped.c for additional directions and
11 * troubleshooting.
12 *
13 * For this sample to work these entries must be present in the
14 * events.xml file. So create an events-threads.xml in the gator
15 * daemon source directory with the following contents and rebuild
16 * gatord:
17 *
18 * <category name="threads">
19 * <event counter="Linux_threads" title="Linux" name="Threads" class="activity" activity1="odd" activity_color1="0x000000ff" rendering_type="bar" average_selection="yes" average_cores="yes" percentage="yes" description="Linux syscall activity"/>
20 * </category>
21 */
22
23#include <trace/events/sched.h>
24
25#include "gator.h"
26
27static ulong threads_enabled;
28static ulong threads_key;
29static ulong threads_cores;
30
31#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
32GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct rq *rq, struct task_struct *prev, struct task_struct *next))
33#else
34GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct task_struct *prev, struct task_struct *next))
35#endif
36{
37 int cpu = get_physical_cpu();
38 int pid = next->pid;
39 if (pid == 0) {
40 // idle
41 gator_marshal_activity_switch(cpu, threads_key, 0, 0);
42 } else if (pid & 1) {
43 // odd
44 gator_marshal_activity_switch(cpu, threads_key, 1, pid);
45 } else {
46 // even
47 //gator_marshal_activity_switch(cpu, threads_key, 2, current->pid);
48 // Multiple activities are not yet supported so emit idle
49 gator_marshal_activity_switch(cpu, threads_key, 0, 0);
50 }
51}
52
53// Adds Linux_threads directory and enabled, key, and cores files to /dev/gator/events
54static int gator_events_threads_create_files(struct super_block *sb, struct dentry *root)
55{
56 struct dentry *dir;
57
58 dir = gatorfs_mkdir(sb, root, "Linux_threads");
59 if (!dir) {
60 return -1;
61 }
62 gatorfs_create_ulong(sb, dir, "enabled", &threads_enabled);
63 gatorfs_create_ro_ulong(sb, dir, "key", &threads_key);
64 // Number of cores associated with this activity
65 gatorfs_create_ro_ulong(sb, dir, "cores", &threads_cores);
66
67 return 0;
68}
69
70static int gator_events_threads_start(void)
71{
72 int cpu;
73
74 if (threads_enabled) {
75 preempt_disable();
76 for (cpu = 0; cpu < nr_cpu_ids; ++cpu) {
77 gator_marshal_activity_switch(cpu, threads_key, 0, 0);
78 }
79 preempt_enable();
80
81 if (GATOR_REGISTER_TRACE(sched_switch)) {
82 goto fail_sched_switch;
83 }
84 }
85
86 return 0;
87
88fail_sched_switch:
89 return -1;
90}
91
92static void gator_events_threads_stop(void)
93{
94 if (threads_enabled) {
95 GATOR_UNREGISTER_TRACE(sched_switch);
96 }
97
98 threads_enabled = 0;
99}
100
101static struct gator_interface gator_events_threads_interface = {
102 .create_files = gator_events_threads_create_files,
103 .start = gator_events_threads_start,
104 .stop = gator_events_threads_stop,
105};
106
107// Must not be static. Ensure that this init function is added to GATOR_EVENTS_LIST in gator_main.c
108int __init gator_events_threads_init(void)
109{
110 threads_enabled = 0;
111 threads_key = gator_events_get_key();
112 threads_cores = nr_cpu_ids;
113
114 return gator_events_install(&gator_events_threads_interface);
115}
diff --git a/drivers/gator/gator_fs.c b/drivers/gator/gator_fs.c
new file mode 100644
index 00000000000..166cfe7d681
--- /dev/null
+++ b/drivers/gator/gator_fs.c
@@ -0,0 +1,365 @@
1/**
2 * @file gatorfs.c
3 *
4 * @remark Copyright 2002 OProfile authors
5 * @remark Read the file COPYING
6 *
7 * @author John Levon
8 *
9 * A simple filesystem for configuration and
10 * access of oprofile.
11 */
12
13#include <linux/init.h>
14#include <linux/module.h>
15#include <linux/fs.h>
16#include <linux/pagemap.h>
17#include <asm/uaccess.h>
18
19#define gatorfs_MAGIC 0x24051020
20#define TMPBUFSIZE 50
21DEFINE_SPINLOCK(gatorfs_lock);
22
23static struct inode *gatorfs_get_inode(struct super_block *sb, int mode)
24{
25 struct inode *inode = new_inode(sb);
26
27 if (inode) {
28#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
29 inode->i_ino = get_next_ino();
30#endif
31 inode->i_mode = mode;
32 inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
33 }
34 return inode;
35}
36
37static const struct super_operations s_ops = {
38 .statfs = simple_statfs,
39 .drop_inode = generic_delete_inode,
40};
41
42static ssize_t gatorfs_ulong_to_user(unsigned long val, char __user *buf, size_t count, loff_t *offset)
43{
44 char tmpbuf[TMPBUFSIZE];
45 size_t maxlen = snprintf(tmpbuf, TMPBUFSIZE, "%lu\n", val);
46 if (maxlen > TMPBUFSIZE)
47 maxlen = TMPBUFSIZE;
48 return simple_read_from_buffer(buf, count, offset, tmpbuf, maxlen);
49}
50
51static ssize_t gatorfs_u64_to_user(u64 val, char __user *buf, size_t count, loff_t *offset)
52{
53 char tmpbuf[TMPBUFSIZE];
54 size_t maxlen = snprintf(tmpbuf, TMPBUFSIZE, "%llu\n", val);
55 if (maxlen > TMPBUFSIZE)
56 maxlen = TMPBUFSIZE;
57 return simple_read_from_buffer(buf, count, offset, tmpbuf, maxlen);
58}
59
60static int gatorfs_ulong_from_user(unsigned long *val, char const __user *buf, size_t count)
61{
62 char tmpbuf[TMPBUFSIZE];
63 unsigned long flags;
64
65 if (!count)
66 return 0;
67
68 if (count > TMPBUFSIZE - 1)
69 return -EINVAL;
70
71 memset(tmpbuf, 0x0, TMPBUFSIZE);
72
73 if (copy_from_user(tmpbuf, buf, count))
74 return -EFAULT;
75
76 spin_lock_irqsave(&gatorfs_lock, flags);
77 *val = simple_strtoul(tmpbuf, NULL, 0);
78 spin_unlock_irqrestore(&gatorfs_lock, flags);
79 return 0;
80}
81
82static int gatorfs_u64_from_user(u64 *val, char const __user *buf, size_t count)
83{
84 char tmpbuf[TMPBUFSIZE];
85 unsigned long flags;
86
87 if (!count)
88 return 0;
89
90 if (count > TMPBUFSIZE - 1)
91 return -EINVAL;
92
93 memset(tmpbuf, 0x0, TMPBUFSIZE);
94
95 if (copy_from_user(tmpbuf, buf, count))
96 return -EFAULT;
97
98 spin_lock_irqsave(&gatorfs_lock, flags);
99 *val = simple_strtoull(tmpbuf, NULL, 0);
100 spin_unlock_irqrestore(&gatorfs_lock, flags);
101 return 0;
102}
103
104static ssize_t ulong_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset)
105{
106 unsigned long *val = file->private_data;
107 return gatorfs_ulong_to_user(*val, buf, count, offset);
108}
109
110static ssize_t u64_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset)
111{
112 u64 *val = file->private_data;
113 return gatorfs_u64_to_user(*val, buf, count, offset);
114}
115
116static ssize_t ulong_write_file(struct file *file, char const __user *buf, size_t count, loff_t *offset)
117{
118 unsigned long *value = file->private_data;
119 int retval;
120
121 if (*offset)
122 return -EINVAL;
123
124 retval = gatorfs_ulong_from_user(value, buf, count);
125
126 if (retval)
127 return retval;
128 return count;
129}
130
131static ssize_t u64_write_file(struct file *file, char const __user *buf, size_t count, loff_t *offset)
132{
133 u64 *value = file->private_data;
134 int retval;
135
136 if (*offset)
137 return -EINVAL;
138
139 retval = gatorfs_u64_from_user(value, buf, count);
140
141 if (retval)
142 return retval;
143 return count;
144}
145
146static int default_open(struct inode *inode, struct file *filp)
147{
148 if (inode->i_private)
149 filp->private_data = inode->i_private;
150 return 0;
151}
152
153static const struct file_operations ulong_fops = {
154 .read = ulong_read_file,
155 .write = ulong_write_file,
156 .open = default_open,
157};
158
159static const struct file_operations u64_fops = {
160 .read = u64_read_file,
161 .write = u64_write_file,
162 .open = default_open,
163};
164
165static const struct file_operations ulong_ro_fops = {
166 .read = ulong_read_file,
167 .open = default_open,
168};
169
170static const struct file_operations u64_ro_fops = {
171 .read = u64_read_file,
172 .open = default_open,
173};
174
175static struct dentry *__gatorfs_create_file(struct super_block *sb,
176 struct dentry *root,
177 char const *name,
178 const struct file_operations *fops,
179 int perm)
180{
181 struct dentry *dentry;
182 struct inode *inode;
183
184 dentry = d_alloc_name(root, name);
185 if (!dentry)
186 return NULL;
187 inode = gatorfs_get_inode(sb, S_IFREG | perm);
188 if (!inode) {
189 dput(dentry);
190 return NULL;
191 }
192 inode->i_fop = fops;
193 d_add(dentry, inode);
194 return dentry;
195}
196
197int gatorfs_create_ulong(struct super_block *sb, struct dentry *root,
198 char const *name, unsigned long *val)
199{
200 struct dentry *d = __gatorfs_create_file(sb, root, name,
201 &ulong_fops, 0644);
202 if (!d)
203 return -EFAULT;
204
205 d->d_inode->i_private = val;
206 return 0;
207}
208
209static int gatorfs_create_u64(struct super_block *sb, struct dentry *root,
210 char const *name, u64 *val)
211{
212 struct dentry *d = __gatorfs_create_file(sb, root, name,
213 &u64_fops, 0644);
214 if (!d)
215 return -EFAULT;
216
217 d->d_inode->i_private = val;
218 return 0;
219}
220
221int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root,
222 char const *name, unsigned long *val)
223{
224 struct dentry *d = __gatorfs_create_file(sb, root, name,
225 &ulong_ro_fops, 0444);
226 if (!d)
227 return -EFAULT;
228
229 d->d_inode->i_private = val;
230 return 0;
231}
232
233static int gatorfs_create_ro_u64(struct super_block *sb, struct dentry *root,
234 char const *name, u64 * val)
235{
236 struct dentry *d =
237 __gatorfs_create_file(sb, root, name, &u64_ro_fops, 0444);
238 if (!d)
239 return -EFAULT;
240
241 d->d_inode->i_private = val;
242 return 0;
243}
244
245static ssize_t atomic_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset)
246{
247 atomic_t *val = file->private_data;
248 return gatorfs_ulong_to_user(atomic_read(val), buf, count, offset);
249}
250
251static const struct file_operations atomic_ro_fops = {
252 .read = atomic_read_file,
253 .open = default_open,
254};
255
256static int gatorfs_create_file(struct super_block *sb, struct dentry *root,
257 char const *name, const struct file_operations *fops)
258{
259 if (!__gatorfs_create_file(sb, root, name, fops, 0644))
260 return -EFAULT;
261 return 0;
262}
263
264static int gatorfs_create_file_perm(struct super_block *sb, struct dentry *root,
265 char const *name,
266 const struct file_operations *fops, int perm)
267{
268 if (!__gatorfs_create_file(sb, root, name, fops, perm))
269 return -EFAULT;
270 return 0;
271}
272
273struct dentry *gatorfs_mkdir(struct super_block *sb,
274 struct dentry *root, char const *name)
275{
276 struct dentry *dentry;
277 struct inode *inode;
278
279 dentry = d_alloc_name(root, name);
280 if (!dentry)
281 return NULL;
282 inode = gatorfs_get_inode(sb, S_IFDIR | 0755);
283 if (!inode) {
284 dput(dentry);
285 return NULL;
286 }
287 inode->i_op = &simple_dir_inode_operations;
288 inode->i_fop = &simple_dir_operations;
289 d_add(dentry, inode);
290 return dentry;
291}
292
293static int gatorfs_fill_super(struct super_block *sb, void *data, int silent)
294{
295 struct inode *root_inode;
296 struct dentry *root_dentry;
297
298 sb->s_blocksize = PAGE_CACHE_SIZE;
299 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
300 sb->s_magic = gatorfs_MAGIC;
301 sb->s_op = &s_ops;
302 sb->s_time_gran = 1;
303
304 root_inode = gatorfs_get_inode(sb, S_IFDIR | 0755);
305 if (!root_inode)
306 return -ENOMEM;
307 root_inode->i_op = &simple_dir_inode_operations;
308 root_inode->i_fop = &simple_dir_operations;
309
310#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)
311 root_dentry = d_alloc_root(root_inode);
312#else
313 root_dentry = d_make_root(root_inode);
314#endif
315
316 if (!root_dentry) {
317#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)
318 iput(root_inode);
319#endif
320 return -ENOMEM;
321 }
322
323 sb->s_root = root_dentry;
324
325 gator_op_create_files(sb, root_dentry);
326
327 return 0;
328}
329
330#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
331static int gatorfs_get_sb(struct file_system_type *fs_type,
332 int flags, const char *dev_name, void *data,
333 struct vfsmount *mnt)
334{
335 return get_sb_single(fs_type, flags, data, gatorfs_fill_super, mnt);
336}
337#else
338static struct dentry *gatorfs_mount(struct file_system_type *fs_type,
339 int flags, const char *dev_name, void *data)
340{
341 return mount_nodev(fs_type, flags, data, gatorfs_fill_super);
342}
343#endif
344
345static struct file_system_type gatorfs_type = {
346 .owner = THIS_MODULE,
347 .name = "gatorfs",
348#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
349 .get_sb = gatorfs_get_sb,
350#else
351 .mount = gatorfs_mount,
352#endif
353
354 .kill_sb = kill_litter_super,
355};
356
357static int __init gatorfs_register(void)
358{
359 return register_filesystem(&gatorfs_type);
360}
361
362static void gatorfs_unregister(void)
363{
364 unregister_filesystem(&gatorfs_type);
365}
diff --git a/drivers/gator/gator_hrtimer_gator.c b/drivers/gator/gator_hrtimer_gator.c
new file mode 100644
index 00000000000..76584554b00
--- /dev/null
+++ b/drivers/gator/gator_hrtimer_gator.c
@@ -0,0 +1,80 @@
1/**
2 * Copyright (C) ARM Limited 2011-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10void (*callback)(void);
11DEFINE_PER_CPU(struct hrtimer, percpu_hrtimer);
12DEFINE_PER_CPU(ktime_t, hrtimer_expire);
13DEFINE_PER_CPU(int, hrtimer_is_active);
14static ktime_t profiling_interval;
15static void gator_hrtimer_online(void);
16static void gator_hrtimer_offline(void);
17
18static enum hrtimer_restart gator_hrtimer_notify(struct hrtimer *hrtimer)
19{
20 int cpu = get_logical_cpu();
21 hrtimer_forward(hrtimer, per_cpu(hrtimer_expire, cpu), profiling_interval);
22 per_cpu(hrtimer_expire, cpu) = ktime_add(per_cpu(hrtimer_expire, cpu), profiling_interval);
23 (*callback)();
24 return HRTIMER_RESTART;
25}
26
27static void gator_hrtimer_online(void)
28{
29 int cpu = get_logical_cpu();
30 struct hrtimer *hrtimer = &per_cpu(percpu_hrtimer, cpu);
31
32 if (per_cpu(hrtimer_is_active, cpu) || profiling_interval.tv64 == 0)
33 return;
34
35 per_cpu(hrtimer_is_active, cpu) = 1;
36 hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
37 hrtimer->function = gator_hrtimer_notify;
38#ifdef CONFIG_PREEMPT_RT_BASE
39 hrtimer->irqsafe = 1;
40#endif
41 per_cpu(hrtimer_expire, cpu) = ktime_add(hrtimer->base->get_time(), profiling_interval);
42 hrtimer_start(hrtimer, per_cpu(hrtimer_expire, cpu), HRTIMER_MODE_ABS_PINNED);
43}
44
45static void gator_hrtimer_offline(void)
46{
47 int cpu = get_logical_cpu();
48 struct hrtimer *hrtimer = &per_cpu(percpu_hrtimer, cpu);
49
50 if (!per_cpu(hrtimer_is_active, cpu))
51 return;
52
53 per_cpu(hrtimer_is_active, cpu) = 0;
54 hrtimer_cancel(hrtimer);
55}
56
57static int gator_hrtimer_init(int interval, void (*func)(void))
58{
59 int cpu;
60
61 (callback) = (func);
62
63 for_each_present_cpu(cpu) {
64 per_cpu(hrtimer_is_active, cpu) = 0;
65 }
66
67 // calculate profiling interval
68 if (interval > 0) {
69 profiling_interval = ns_to_ktime(1000000000UL / interval);
70 } else {
71 profiling_interval.tv64 = 0;
72 }
73
74 return 0;
75}
76
77static void gator_hrtimer_shutdown(void)
78{
79 /* empty */
80}
diff --git a/drivers/gator/gator_iks.c b/drivers/gator/gator_iks.c
new file mode 100644
index 00000000000..9180b874457
--- /dev/null
+++ b/drivers/gator/gator_iks.c
@@ -0,0 +1,197 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10#if GATOR_IKS_SUPPORT
11
12#include <linux/of.h>
13#include <asm/bL_switcher.h>
14#include <asm/smp_plat.h>
15#include <trace/events/power_cpu_migrate.h>
16
17static bool map_cpuids;
18static int mpidr_cpuids[NR_CPUS];
19static const struct gator_cpu * mpidr_cpus[NR_CPUS];
20static int __lcpu_to_pcpu[NR_CPUS];
21
22static const struct gator_cpu *gator_find_cpu_by_dt_name(const char *const name)
23{
24 int i;
25
26 for (i = 0; gator_cpus[i].cpuid != 0; ++i) {
27 const struct gator_cpu *const gator_cpu = &gator_cpus[i];
28 if (gator_cpu->dt_name != NULL && strcmp(gator_cpu->dt_name, name) == 0) {
29 return gator_cpu;
30 }
31 }
32
33 return NULL;
34}
35
36static void calc_first_cluster_size(void)
37{
38 int len;
39 const u32 *val;
40 const char *compatible;
41 struct device_node *cn = NULL;
42 int mpidr_cpuids_count = 0;
43
44 // Zero is a valid cpuid, so initialize the array to 0xff's
45 memset(&mpidr_cpuids, 0xff, sizeof(mpidr_cpuids));
46 memset(&mpidr_cpus, 0, sizeof(mpidr_cpus));
47
48 while ((cn = of_find_node_by_type(cn, "cpu"))) {
49 BUG_ON(mpidr_cpuids_count >= NR_CPUS);
50
51 val = of_get_property(cn, "reg", &len);
52 if (!val || len != 4) {
53 pr_err("%s missing reg property\n", cn->full_name);
54 continue;
55 }
56 compatible = of_get_property(cn, "compatible", NULL);
57 if (compatible == NULL) {
58 pr_err("%s missing compatible property\n", cn->full_name);
59 continue;
60 }
61
62 mpidr_cpuids[mpidr_cpuids_count] = be32_to_cpup(val);
63 mpidr_cpus[mpidr_cpuids_count] = gator_find_cpu_by_dt_name(compatible);
64 ++mpidr_cpuids_count;
65 }
66
67 map_cpuids = (mpidr_cpuids_count == nr_cpu_ids);
68}
69
70static int linearize_mpidr(int mpidr)
71{
72 int i;
73 for (i = 0; i < nr_cpu_ids; ++i) {
74 if (mpidr_cpuids[i] == mpidr) {
75 return i;
76 }
77 }
78
79 BUG();
80}
81
82int lcpu_to_pcpu(const int lcpu)
83{
84 int pcpu;
85
86 if (!map_cpuids)
87 return lcpu;
88
89 BUG_ON(lcpu >= nr_cpu_ids || lcpu < 0);
90 pcpu = __lcpu_to_pcpu[lcpu];
91 BUG_ON(pcpu >= nr_cpu_ids || pcpu < 0);
92 return pcpu;
93}
94
95int pcpu_to_lcpu(const int pcpu)
96{
97 int lcpu;
98
99 if (!map_cpuids)
100 return pcpu;
101
102 BUG_ON(pcpu >= nr_cpu_ids || pcpu < 0);
103 for (lcpu = 0; lcpu < nr_cpu_ids; ++lcpu) {
104 if (__lcpu_to_pcpu[lcpu] == pcpu) {
105 BUG_ON(lcpu >= nr_cpu_ids || lcpu < 0);
106 return lcpu;
107 }
108 }
109 BUG();
110}
111
112static void gator_update_cpu_mapping(u32 cpu_hwid)
113{
114 int lcpu = smp_processor_id();
115 int pcpu = linearize_mpidr(cpu_hwid & MPIDR_HWID_BITMASK);
116 BUG_ON(lcpu >= nr_cpu_ids || lcpu < 0);
117 BUG_ON(pcpu >= nr_cpu_ids || pcpu < 0);
118 __lcpu_to_pcpu[lcpu] = pcpu;
119}
120
121GATOR_DEFINE_PROBE(cpu_migrate_begin, TP_PROTO(u64 timestamp, u32 cpu_hwid))
122{
123 const int cpu = get_physical_cpu();
124
125 gator_timer_offline((void *)1);
126 gator_timer_offline_dispatch(cpu, true);
127}
128
129GATOR_DEFINE_PROBE(cpu_migrate_finish, TP_PROTO(u64 timestamp, u32 cpu_hwid))
130{
131 int cpu;
132
133 gator_update_cpu_mapping(cpu_hwid);
134
135 // get_physical_cpu must be called after gator_update_cpu_mapping
136 cpu = get_physical_cpu();
137 gator_timer_online_dispatch(cpu, true);
138 gator_timer_online((void *)1);
139}
140
141GATOR_DEFINE_PROBE(cpu_migrate_current, TP_PROTO(u64 timestamp, u32 cpu_hwid))
142{
143 gator_update_cpu_mapping(cpu_hwid);
144}
145
146static void gator_send_iks_core_names(void)
147{
148 int cpu;
149 // Send the cpu names
150 preempt_disable();
151 for (cpu = 0; cpu < nr_cpu_ids; ++cpu) {
152 if (mpidr_cpus[cpu] != NULL) {
153 gator_send_core_name(cpu, mpidr_cpus[cpu]->cpuid);
154 }
155 }
156 preempt_enable();
157}
158
159static int gator_migrate_start(void)
160{
161 int retval = 0;
162
163 if (!map_cpuids)
164 return retval;
165
166 if (retval == 0)
167 retval = GATOR_REGISTER_TRACE(cpu_migrate_begin);
168 if (retval == 0)
169 retval = GATOR_REGISTER_TRACE(cpu_migrate_finish);
170 if (retval == 0)
171 retval = GATOR_REGISTER_TRACE(cpu_migrate_current);
172 if (retval == 0) {
173 // Initialize the logical to physical cpu mapping
174 memset(&__lcpu_to_pcpu, 0xff, sizeof(__lcpu_to_pcpu));
175 bL_switcher_trace_trigger();
176 }
177 return retval;
178}
179
180static void gator_migrate_stop(void)
181{
182 if (!map_cpuids)
183 return;
184
185 GATOR_UNREGISTER_TRACE(cpu_migrate_current);
186 GATOR_UNREGISTER_TRACE(cpu_migrate_finish);
187 GATOR_UNREGISTER_TRACE(cpu_migrate_begin);
188}
189
190#else
191
192#define calc_first_cluster_size()
193#define gator_send_iks_core_names()
194#define gator_migrate_start() 0
195#define gator_migrate_stop()
196
197#endif
diff --git a/drivers/gator/gator_main.c b/drivers/gator/gator_main.c
new file mode 100644
index 00000000000..0d867f22364
--- /dev/null
+++ b/drivers/gator/gator_main.c
@@ -0,0 +1,1460 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10// This version must match the gator daemon version
11#define PROTOCOL_VERSION 19
12static unsigned long gator_protocol_version = PROTOCOL_VERSION;
13
14#include <linux/slab.h>
15#include <linux/cpu.h>
16#include <linux/sched.h>
17#include <linux/irq.h>
18#include <linux/vmalloc.h>
19#include <linux/hardirq.h>
20#include <linux/highmem.h>
21#include <linux/pagemap.h>
22#include <linux/suspend.h>
23#include <linux/module.h>
24#include <linux/perf_event.h>
25#include <linux/utsname.h>
26#include <linux/kthread.h>
27#include <asm/stacktrace.h>
28#include <asm/uaccess.h>
29
30#include "gator.h"
31
32#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
33#error kernels prior to 2.6.32 are not supported
34#endif
35
36#if defined(MODULE) && !defined(CONFIG_MODULES)
37#error Cannot build a module against a kernel that does not support modules. To resolve, either rebuild the kernel to support modules or build gator as part of the kernel.
38#endif
39
40#if !defined(CONFIG_GENERIC_TRACER) && !defined(CONFIG_TRACING)
41#error gator requires the kernel to have CONFIG_GENERIC_TRACER or CONFIG_TRACING defined
42#endif
43
44#ifndef CONFIG_PROFILING
45#error gator requires the kernel to have CONFIG_PROFILING defined
46#endif
47
48#ifndef CONFIG_HIGH_RES_TIMERS
49#error gator requires the kernel to have CONFIG_HIGH_RES_TIMERS defined to support PC sampling
50#endif
51
52#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0) && defined(__arm__) && defined(CONFIG_SMP) && !defined(CONFIG_LOCAL_TIMERS)
53#error gator requires the kernel to have CONFIG_LOCAL_TIMERS defined on SMP systems
54#endif
55
56#if (GATOR_PERF_SUPPORT) && (!(GATOR_PERF_PMU_SUPPORT))
57#ifndef CONFIG_PERF_EVENTS
58#error gator requires the kernel to have CONFIG_PERF_EVENTS defined to support pmu hardware counters
59#elif !defined CONFIG_HW_PERF_EVENTS
60#error gator requires the kernel to have CONFIG_HW_PERF_EVENTS defined to support pmu hardware counters
61#endif
62#endif
63
64/******************************************************************************
65 * DEFINES
66 ******************************************************************************/
67#define SUMMARY_BUFFER_SIZE (1*1024)
68#define BACKTRACE_BUFFER_SIZE (128*1024)
69#define NAME_BUFFER_SIZE (64*1024)
70#define COUNTER_BUFFER_SIZE (64*1024) // counters have the core as part of the data and the core value in the frame header may be discarded
71#define BLOCK_COUNTER_BUFFER_SIZE (128*1024)
72#define ANNOTATE_BUFFER_SIZE (128*1024) // annotate counters have the core as part of the data and the core value in the frame header may be discarded
73#define SCHED_TRACE_BUFFER_SIZE (128*1024)
74#define IDLE_BUFFER_SIZE (32*1024) // idle counters have the core as part of the data and the core value in the frame header may be discarded
75#define ACTIVITY_BUFFER_SIZE (128*1024)
76
77#define NO_COOKIE 0U
78#define UNRESOLVED_COOKIE ~0U
79
80#define FRAME_SUMMARY 1
81#define FRAME_BACKTRACE 2
82#define FRAME_NAME 3
83#define FRAME_COUNTER 4
84#define FRAME_BLOCK_COUNTER 5
85#define FRAME_ANNOTATE 6
86#define FRAME_SCHED_TRACE 7
87#define FRAME_IDLE 9
88#define FRAME_ACTIVITY 13
89
90#define MESSAGE_END_BACKTRACE 1
91
92// Name Frame Messages
93#define MESSAGE_COOKIE 1
94#define MESSAGE_THREAD_NAME 2
95#define MESSAGE_LINK 4
96
97// Scheduler Trace Frame Messages
98#define MESSAGE_SCHED_SWITCH 1
99#define MESSAGE_SCHED_EXIT 2
100
101// Idle Frame Messages
102#define MESSAGE_IDLE_ENTER 1
103#define MESSAGE_IDLE_EXIT 2
104
105// Summary Frame Messages
106#define MESSAGE_SUMMARY 1
107#define MESSAGE_CORE_NAME 3
108
109// Activity Frame Messages
110#define MESSAGE_SWITCH 2
111#define MESSAGE_EXIT 3
112
113#define MAXSIZE_PACK32 5
114#define MAXSIZE_PACK64 10
115
116#define FRAME_HEADER_SIZE 3
117
118#if defined(__arm__)
119#define PC_REG regs->ARM_pc
120#elif defined(__aarch64__)
121#define PC_REG regs->pc
122#else
123#define PC_REG regs->ip
124#endif
125
126enum {
127 SUMMARY_BUF,
128 BACKTRACE_BUF,
129 NAME_BUF,
130 COUNTER_BUF,
131 BLOCK_COUNTER_BUF,
132 ANNOTATE_BUF,
133 SCHED_TRACE_BUF,
134 IDLE_BUF,
135 ACTIVITY_BUF,
136 NUM_GATOR_BUFS
137};
138
139/******************************************************************************
140 * Globals
141 ******************************************************************************/
142static unsigned long gator_cpu_cores;
143// Size of the largest buffer. Effectively constant, set in gator_op_create_files
144static unsigned long userspace_buffer_size;
145static unsigned long gator_backtrace_depth;
146// How often to commit the buffers for live in nanoseconds
147static u64 gator_live_rate;
148
149static unsigned long gator_started;
150static u64 gator_monotonic_started;
151static u64 gator_hibernate_time;
152static unsigned long gator_buffer_opened;
153static unsigned long gator_timer_count;
154static unsigned long gator_response_type;
155static DEFINE_MUTEX(start_mutex);
156static DEFINE_MUTEX(gator_buffer_mutex);
157
158bool event_based_sampling;
159
160static DECLARE_WAIT_QUEUE_HEAD(gator_buffer_wait);
161static DECLARE_WAIT_QUEUE_HEAD(gator_annotate_wait);
162static struct timer_list gator_buffer_wake_up_timer;
163static bool gator_buffer_wake_run;
164// Initialize semaphore unlocked to initialize memory values
165#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
166static DECLARE_MUTEX(gator_buffer_wake_sem);
167#else
168static DEFINE_SEMAPHORE(gator_buffer_wake_sem);
169#endif
170static struct task_struct *gator_buffer_wake_thread;
171static LIST_HEAD(gator_events);
172
173static DEFINE_PER_CPU(u64, last_timestamp);
174
175static bool printed_monotonic_warning;
176
177static u32 gator_cpuids[NR_CPUS];
178static bool sent_core_name[NR_CPUS];
179
180static DEFINE_PER_CPU(bool, in_scheduler_context);
181
182/******************************************************************************
183 * Prototypes
184 ******************************************************************************/
185static u64 gator_get_time(void);
186static void gator_op_create_files(struct super_block *sb, struct dentry *root);
187
188// gator_buffer is protected by being per_cpu and by having IRQs disabled when writing to it.
189// Most marshal_* calls take care of this except for marshal_cookie*, marshal_backtrace* and marshal_frame where the caller is responsible for doing so.
190// No synchronization is needed with the backtrace buffer as it is per cpu and is only used from the hrtimer.
191// The annotate_lock must be held when using the annotation buffer as it is not per cpu.
192// collect_counters which is the sole writer to the block counter frame is additionally protected by the per cpu collecting flag
193
194// Size of the buffer, must be a power of 2. Effectively constant, set in gator_op_setup.
195static uint32_t gator_buffer_size[NUM_GATOR_BUFS];
196// gator_buffer_size - 1, bitwise and with pos to get offset into the array. Effectively constant, set in gator_op_setup.
197static uint32_t gator_buffer_mask[NUM_GATOR_BUFS];
198// Read position in the buffer. Initialized to zero in gator_op_setup and incremented after bytes are read by userspace in userspace_buffer_read
199static DEFINE_PER_CPU(int[NUM_GATOR_BUFS], gator_buffer_read);
200// Write position in the buffer. Initialized to zero in gator_op_setup and incremented after bytes are written to the buffer
201static DEFINE_PER_CPU(int[NUM_GATOR_BUFS], gator_buffer_write);
202// Commit position in the buffer. Initialized to zero in gator_op_setup and incremented after a frame is ready to be read by userspace
203static DEFINE_PER_CPU(int[NUM_GATOR_BUFS], gator_buffer_commit);
204// If set to false, decreases the number of bytes returned by buffer_bytes_available. Set in buffer_check_space if no space is remaining. Initialized to true in gator_op_setup
205// This means that if we run out of space, continue to report that no space is available until bytes are read by userspace
206static DEFINE_PER_CPU(int[NUM_GATOR_BUFS], buffer_space_available);
207// The buffer. Allocated in gator_op_setup
208static DEFINE_PER_CPU(char *[NUM_GATOR_BUFS], gator_buffer);
209// The time after which the buffer should be committed for live display
210static DEFINE_PER_CPU(u64, gator_buffer_commit_time);
211
212// List of all gator events - new events must be added to this list
213#define GATOR_EVENTS_LIST \
214 GATOR_EVENT(gator_events_armv6_init) \
215 GATOR_EVENT(gator_events_armv7_init) \
216 GATOR_EVENT(gator_events_block_init) \
217 GATOR_EVENT(gator_events_ccn504_init) \
218 GATOR_EVENT(gator_events_irq_init) \
219 GATOR_EVENT(gator_events_l2c310_init) \
220 GATOR_EVENT(gator_events_mali_init) \
221 GATOR_EVENT(gator_events_mali_t6xx_hw_init) \
222 GATOR_EVENT(gator_events_mali_t6xx_init) \
223 GATOR_EVENT(gator_events_meminfo_init) \
224 GATOR_EVENT(gator_events_mmapped_init) \
225 GATOR_EVENT(gator_events_net_init) \
226 GATOR_EVENT(gator_events_perf_pmu_init) \
227 GATOR_EVENT(gator_events_sched_init) \
228 GATOR_EVENT(gator_events_scorpion_init) \
229 GATOR_EVENT(gator_events_threads_init) \
230
231#define GATOR_EVENT(EVENT_INIT) __weak int EVENT_INIT(void);
232GATOR_EVENTS_LIST
233#undef GATOR_EVENT
234
235static int (*gator_events_list[])(void) = {
236#define GATOR_EVENT(EVENT_INIT) EVENT_INIT,
237GATOR_EVENTS_LIST
238#undef GATOR_EVENT
239};
240
241/******************************************************************************
242 * Application Includes
243 ******************************************************************************/
244#include "gator_fs.c"
245#include "gator_buffer_write.c"
246#include "gator_buffer.c"
247#include "gator_marshaling.c"
248#include "gator_hrtimer_gator.c"
249#include "gator_cookies.c"
250#include "gator_annotate.c"
251#include "gator_trace_sched.c"
252#include "gator_trace_power.c"
253#include "gator_trace_gpu.c"
254#include "gator_backtrace.c"
255
256/******************************************************************************
257 * Misc
258 ******************************************************************************/
259
260static const struct gator_cpu gator_cpus[] = {
261 {
262 .cpuid = ARM1136,
263 .core_name = "ARM1136",
264 .pmnc_name = "ARM_ARM11",
265 .dt_name = "arm,arm1136",
266 .pmnc_counters = 3,
267 },
268 {
269 .cpuid = ARM1156,
270 .core_name = "ARM1156",
271 .pmnc_name = "ARM_ARM11",
272 .dt_name = "arm,arm1156",
273 .pmnc_counters = 3,
274 },
275 {
276 .cpuid = ARM1176,
277 .core_name = "ARM1176",
278 .pmnc_name = "ARM_ARM11",
279 .dt_name = "arm,arm1176",
280 .pmnc_counters = 3,
281 },
282 {
283 .cpuid = ARM11MPCORE,
284 .core_name = "ARM11MPCore",
285 .pmnc_name = "ARM_ARM11MPCore",
286 .dt_name = "arm,arm11mpcore",
287 .pmnc_counters = 3,
288 },
289 {
290 .cpuid = CORTEX_A5,
291 .core_name = "Cortex-A5",
292 .pmnc_name = "ARMv7_Cortex_A5",
293 .dt_name = "arm,cortex-a5",
294 .pmnc_counters = 2,
295 },
296 {
297 .cpuid = CORTEX_A7,
298 .core_name = "Cortex-A7",
299 .pmnc_name = "ARMv7_Cortex_A7",
300 .dt_name = "arm,cortex-a7",
301 .pmnc_counters = 4,
302 },
303 {
304 .cpuid = CORTEX_A8,
305 .core_name = "Cortex-A8",
306 .pmnc_name = "ARMv7_Cortex_A8",
307 .dt_name = "arm,cortex-a8",
308 .pmnc_counters = 4,
309 },
310 {
311 .cpuid = CORTEX_A9,
312 .core_name = "Cortex-A9",
313 .pmnc_name = "ARMv7_Cortex_A9",
314 .dt_name = "arm,cortex-a9",
315 .pmnc_counters = 6,
316 },
317 {
318 .cpuid = CORTEX_A12,
319 .core_name = "Cortex-A12",
320 .pmnc_name = "ARMv7_Cortex_A12",
321 .dt_name = "arm,cortex-a12",
322 .pmnc_counters = 6,
323 },
324 {
325 .cpuid = CORTEX_A15,
326 .core_name = "Cortex-A15",
327 .pmnc_name = "ARMv7_Cortex_A15",
328 .dt_name = "arm,cortex-a15",
329 .pmnc_counters = 6,
330 },
331 {
332 .cpuid = CORTEX_A17,
333 .core_name = "Cortex-A17",
334 .pmnc_name = "ARMv7_Cortex_A17",
335 .dt_name = "arm,cortex-a17",
336 .pmnc_counters = 6,
337 },
338 {
339 .cpuid = SCORPION,
340 .core_name = "Scorpion",
341 .pmnc_name = "Scorpion",
342 .pmnc_counters = 4,
343 },
344 {
345 .cpuid = SCORPIONMP,
346 .core_name = "ScorpionMP",
347 .pmnc_name = "ScorpionMP",
348 .pmnc_counters = 4,
349 },
350 {
351 .cpuid = KRAITSIM,
352 .core_name = "KraitSIM",
353 .pmnc_name = "Krait",
354 .pmnc_counters = 4,
355 },
356 {
357 .cpuid = KRAIT,
358 .core_name = "Krait",
359 .pmnc_name = "Krait",
360 .pmnc_counters = 4,
361 },
362 {
363 .cpuid = KRAIT_S4_PRO,
364 .core_name = "Krait S4 Pro",
365 .pmnc_name = "Krait",
366 .pmnc_counters = 4,
367 },
368 {
369 .cpuid = CORTEX_A53,
370 .core_name = "Cortex-A53",
371 .pmnc_name = "ARM_Cortex-A53",
372 .dt_name = "arm,cortex-a53",
373 .pmnc_counters = 6,
374 },
375 {
376 .cpuid = CORTEX_A57,
377 .core_name = "Cortex-A57",
378 .pmnc_name = "ARM_Cortex-A57",
379 .dt_name = "arm,cortex-a57",
380 .pmnc_counters = 6,
381 },
382 {
383 .cpuid = AARCH64,
384 .core_name = "AArch64",
385 .pmnc_name = "ARM_AArch64",
386 .pmnc_counters = 6,
387 },
388 {
389 .cpuid = OTHER,
390 .core_name = "Other",
391 .pmnc_name = "Other",
392 .pmnc_counters = 6,
393 },
394 {}
395};
396
397const struct gator_cpu *gator_find_cpu_by_cpuid(const u32 cpuid)
398{
399 int i;
400
401 for (i = 0; gator_cpus[i].cpuid != 0; ++i) {
402 const struct gator_cpu *const gator_cpu = &gator_cpus[i];
403 if (gator_cpu->cpuid == cpuid) {
404 return gator_cpu;
405 }
406 }
407
408 return NULL;
409}
410
411const struct gator_cpu *gator_find_cpu_by_pmu_name(const char *const name)
412{
413 int i;
414
415 for (i = 0; gator_cpus[i].cpuid != 0; ++i) {
416 const struct gator_cpu *const gator_cpu = &gator_cpus[i];
417 if (gator_cpu->pmnc_name != NULL && strcmp(gator_cpu->pmnc_name, name) == 0) {
418 return gator_cpu;
419 }
420 }
421
422 return NULL;
423}
424
425u32 gator_cpuid(void)
426{
427#if defined(__arm__) || defined(__aarch64__)
428 u32 val;
429#if !defined(__aarch64__)
430 asm volatile("mrc p15, 0, %0, c0, c0, 0" : "=r" (val));
431#else
432 asm volatile("mrs %0, midr_el1" : "=r" (val));
433#endif
434 return (val >> 4) & 0xfff;
435#else
436 return OTHER;
437#endif
438}
439
440static void gator_buffer_wake_up(unsigned long data)
441{
442 wake_up(&gator_buffer_wait);
443}
444
445static int gator_buffer_wake_func(void *data)
446{
447 for (;;) {
448 if (down_killable(&gator_buffer_wake_sem)) {
449 break;
450 }
451
452 // Eat up any pending events
453 while (!down_trylock(&gator_buffer_wake_sem));
454
455 if (!gator_buffer_wake_run) {
456 break;
457 }
458
459 gator_buffer_wake_up(0);
460 }
461
462 return 0;
463}
464
465/******************************************************************************
466 * Commit interface
467 ******************************************************************************/
468static bool buffer_commit_ready(int *cpu, int *buftype)
469{
470 int cpu_x, x;
471 for_each_present_cpu(cpu_x) {
472 for (x = 0; x < NUM_GATOR_BUFS; x++)
473 if (per_cpu(gator_buffer_commit, cpu_x)[x] != per_cpu(gator_buffer_read, cpu_x)[x]) {
474 *cpu = cpu_x;
475 *buftype = x;
476 return true;
477 }
478 }
479 *cpu = -1;
480 *buftype = -1;
481 return false;
482}
483
484/******************************************************************************
485 * hrtimer interrupt processing
486 ******************************************************************************/
487static void gator_timer_interrupt(void)
488{
489 struct pt_regs *const regs = get_irq_regs();
490 gator_backtrace_handler(regs);
491}
492
493void gator_backtrace_handler(struct pt_regs *const regs)
494{
495 u64 time = gator_get_time();
496 int cpu = get_physical_cpu();
497
498 // Output backtrace
499 gator_add_sample(cpu, regs, time);
500
501 // Collect counters
502 if (!per_cpu(collecting, cpu)) {
503 collect_counters(time, NULL);
504 }
505
506 // No buffer flushing occurs during sched switch for RT-Preempt full. The block counter frame will be flushed by collect_counters, but the sched buffer needs to be explicitly flushed
507#ifdef CONFIG_PREEMPT_RT_FULL
508 buffer_check(cpu, SCHED_TRACE_BUF, time);
509#endif
510}
511
512static int gator_running;
513
514// This function runs in interrupt context and on the appropriate core
515static void gator_timer_offline(void *migrate)
516{
517 struct gator_interface *gi;
518 int i, len, cpu = get_physical_cpu();
519 int *buffer;
520 u64 time;
521
522 gator_trace_sched_offline();
523 gator_trace_power_offline();
524
525 if (!migrate) {
526 gator_hrtimer_offline();
527 }
528
529 // Offline any events and output counters
530 time = gator_get_time();
531 if (marshal_event_header(time)) {
532 list_for_each_entry(gi, &gator_events, list) {
533 if (gi->offline) {
534 len = gi->offline(&buffer, migrate);
535 marshal_event(len, buffer);
536 }
537 }
538 // Only check after writing all counters so that time and corresponding counters appear in the same frame
539 buffer_check(cpu, BLOCK_COUNTER_BUF, time);
540 }
541
542 // Flush all buffers on this core
543 for (i = 0; i < NUM_GATOR_BUFS; i++)
544 gator_commit_buffer(cpu, i, time);
545}
546
547// This function runs in interrupt context and may be running on a core other than core 'cpu'
548static void gator_timer_offline_dispatch(int cpu, bool migrate)
549{
550 struct gator_interface *gi;
551
552 list_for_each_entry(gi, &gator_events, list) {
553 if (gi->offline_dispatch) {
554 gi->offline_dispatch(cpu, migrate);
555 }
556 }
557}
558
559static void gator_timer_stop(void)
560{
561 int cpu;
562
563 if (gator_running) {
564 on_each_cpu(gator_timer_offline, NULL, 1);
565 for_each_online_cpu(cpu) {
566 gator_timer_offline_dispatch(lcpu_to_pcpu(cpu), false);
567 }
568
569 gator_running = 0;
570 gator_hrtimer_shutdown();
571 }
572}
573
574static void gator_send_core_name(const int cpu, const u32 cpuid)
575{
576#if defined(__arm__) || defined(__aarch64__)
577 if (!sent_core_name[cpu] || (cpuid != gator_cpuids[cpu])) {
578 const struct gator_cpu *const gator_cpu = gator_find_cpu_by_cpuid(cpuid);
579 const char *core_name = NULL;
580 char core_name_buf[32];
581
582 // Save off this cpuid
583 gator_cpuids[cpu] = cpuid;
584 if (gator_cpu != NULL) {
585 core_name = gator_cpu->core_name;
586 } else {
587 if (cpuid == -1) {
588 snprintf(core_name_buf, sizeof(core_name_buf), "Unknown");
589 } else {
590 snprintf(core_name_buf, sizeof(core_name_buf), "Unknown (0x%.3x)", cpuid);
591 }
592 core_name = core_name_buf;
593 }
594
595 marshal_core_name(cpu, cpuid, core_name);
596 sent_core_name[cpu] = true;
597 }
598#endif
599}
600
601static void gator_read_cpuid(void * arg)
602{
603 gator_cpuids[get_physical_cpu()] = gator_cpuid();
604}
605
606// This function runs in interrupt context and on the appropriate core
607static void gator_timer_online(void *migrate)
608{
609 struct gator_interface *gi;
610 int len, cpu = get_physical_cpu();
611 int *buffer;
612 u64 time;
613
614 // Send what is currently running on this core
615 marshal_sched_trace_switch(current->pid, 0);
616
617 gator_trace_power_online();
618
619 // online any events and output counters
620 time = gator_get_time();
621 if (marshal_event_header(time)) {
622 list_for_each_entry(gi, &gator_events, list) {
623 if (gi->online) {
624 len = gi->online(&buffer, migrate);
625 marshal_event(len, buffer);
626 }
627 }
628 // Only check after writing all counters so that time and corresponding counters appear in the same frame
629 buffer_check(cpu, BLOCK_COUNTER_BUF, time);
630 }
631
632 if (!migrate) {
633 gator_hrtimer_online();
634 }
635
636 gator_send_core_name(cpu, gator_cpuid());
637}
638
639// This function runs in interrupt context and may be running on a core other than core 'cpu'
640static void gator_timer_online_dispatch(int cpu, bool migrate)
641{
642 struct gator_interface *gi;
643
644 list_for_each_entry(gi, &gator_events, list) {
645 if (gi->online_dispatch) {
646 gi->online_dispatch(cpu, migrate);
647 }
648 }
649}
650
651#include "gator_iks.c"
652
653static int gator_timer_start(unsigned long sample_rate)
654{
655 int cpu;
656
657 if (gator_running) {
658 pr_notice("gator: already running\n");
659 return 0;
660 }
661
662 gator_running = 1;
663
664 // event based sampling trumps hr timer based sampling
665 if (event_based_sampling) {
666 sample_rate = 0;
667 }
668
669 if (gator_hrtimer_init(sample_rate, gator_timer_interrupt) == -1)
670 return -1;
671
672 // Send off the previously saved cpuids
673 for_each_present_cpu(cpu) {
674 preempt_disable();
675 gator_send_core_name(cpu, gator_cpuids[cpu]);
676 preempt_enable();
677 }
678
679 gator_send_iks_core_names();
680 for_each_online_cpu(cpu) {
681 gator_timer_online_dispatch(lcpu_to_pcpu(cpu), false);
682 }
683 on_each_cpu(gator_timer_online, NULL, 1);
684
685 return 0;
686}
687
688static u64 gator_get_time(void)
689{
690 struct timespec ts;
691 u64 timestamp;
692 u64 prev_timestamp;
693 u64 delta;
694 int cpu = smp_processor_id();
695
696 // Match clock_gettime(CLOCK_MONOTONIC_RAW, &ts) from userspace
697 getrawmonotonic(&ts);
698 timestamp = timespec_to_ns(&ts);
699
700 // getrawmonotonic is not monotonic on all systems. Detect and attempt to correct these cases.
701 // up to 0.5ms delta has been seen on some systems, which can skew Streamline data when viewing at high resolution.
702 // This doesn't work well with interrupts, but that it's OK - the real concern is to catch big jumps in time
703 prev_timestamp = per_cpu(last_timestamp, cpu);
704 if (prev_timestamp <= timestamp) {
705 per_cpu(last_timestamp, cpu) = timestamp;
706 } else {
707 delta = prev_timestamp - timestamp;
708 // Log the error once
709 if (!printed_monotonic_warning && delta > 500000) {
710 printk(KERN_ERR "%s: getrawmonotonic is not monotonic cpu: %i delta: %lli\nSkew in Streamline data may be present at the fine zoom levels\n", __FUNCTION__, cpu, delta);
711 printed_monotonic_warning = true;
712 }
713 timestamp = prev_timestamp;
714 }
715
716 return timestamp - gator_monotonic_started;
717}
718
719/******************************************************************************
720 * cpu hotplug and pm notifiers
721 ******************************************************************************/
722static int __cpuinit gator_hotcpu_notify(struct notifier_block *self, unsigned long action, void *hcpu)
723{
724 int cpu = lcpu_to_pcpu((long)hcpu);
725
726 switch (action) {
727 case CPU_DOWN_PREPARE:
728 case CPU_DOWN_PREPARE_FROZEN:
729 smp_call_function_single(cpu, gator_timer_offline, NULL, 1);
730 gator_timer_offline_dispatch(cpu, false);
731 break;
732 case CPU_ONLINE:
733 case CPU_ONLINE_FROZEN:
734 gator_timer_online_dispatch(cpu, false);
735 smp_call_function_single(cpu, gator_timer_online, NULL, 1);
736 break;
737 }
738
739 return NOTIFY_OK;
740}
741
742static struct notifier_block __refdata gator_hotcpu_notifier = {
743 .notifier_call = gator_hotcpu_notify,
744};
745
746// n.b. calling "on_each_cpu" only runs on those that are online
747// Registered linux events are not disabled, so their counters will continue to collect
748static int gator_pm_notify(struct notifier_block *nb, unsigned long event, void *dummy)
749{
750 int cpu;
751 struct timespec ts;
752
753 switch (event) {
754 case PM_HIBERNATION_PREPARE:
755 case PM_SUSPEND_PREPARE:
756 unregister_hotcpu_notifier(&gator_hotcpu_notifier);
757 unregister_scheduler_tracepoints();
758 on_each_cpu(gator_timer_offline, NULL, 1);
759 for_each_online_cpu(cpu) {
760 gator_timer_offline_dispatch(lcpu_to_pcpu(cpu), false);
761 }
762
763 // Record the wallclock hibernate time
764 getnstimeofday(&ts);
765 gator_hibernate_time = timespec_to_ns(&ts) - gator_get_time();
766 break;
767 case PM_POST_HIBERNATION:
768 case PM_POST_SUSPEND:
769 // Adjust gator_monotonic_started for the time spent sleeping, as gator_get_time does not account for it
770 if (gator_hibernate_time > 0) {
771 getnstimeofday(&ts);
772 gator_monotonic_started += gator_hibernate_time + gator_get_time() - timespec_to_ns(&ts);
773 gator_hibernate_time = 0;
774 }
775
776 for_each_online_cpu(cpu) {
777 gator_timer_online_dispatch(lcpu_to_pcpu(cpu), false);
778 }
779 on_each_cpu(gator_timer_online, NULL, 1);
780 register_scheduler_tracepoints();
781 register_hotcpu_notifier(&gator_hotcpu_notifier);
782 break;
783 }
784
785 return NOTIFY_OK;
786}
787
788static struct notifier_block gator_pm_notifier = {
789 .notifier_call = gator_pm_notify,
790};
791
792static int gator_notifier_start(void)
793{
794 int retval;
795 retval = register_hotcpu_notifier(&gator_hotcpu_notifier);
796 if (retval == 0)
797 retval = register_pm_notifier(&gator_pm_notifier);
798 return retval;
799}
800
801static void gator_notifier_stop(void)
802{
803 unregister_pm_notifier(&gator_pm_notifier);
804 unregister_hotcpu_notifier(&gator_hotcpu_notifier);
805}
806
807/******************************************************************************
808 * Main
809 ******************************************************************************/
810static void gator_summary(void)
811{
812 u64 timestamp, uptime;
813 struct timespec ts;
814 char uname_buf[512];
815 void (*m2b)(struct timespec *ts);
816
817 snprintf(uname_buf, sizeof(uname_buf), "%s %s %s %s %s GNU/Linux", utsname()->sysname, utsname()->nodename, utsname()->release, utsname()->version, utsname()->machine);
818
819 getnstimeofday(&ts);
820 timestamp = timespec_to_ns(&ts);
821
822 do_posix_clock_monotonic_gettime(&ts);
823 // monotonic_to_bootbased is not defined for some versions of Android
824 m2b = symbol_get(monotonic_to_bootbased);
825 if (m2b) {
826 m2b(&ts);
827 }
828 uptime = timespec_to_ns(&ts);
829
830 // Disable preemption as gator_get_time calls smp_processor_id to verify time is monotonic
831 preempt_disable();
832 // Set monotonic_started to zero as gator_get_time is uptime minus monotonic_started
833 gator_monotonic_started = 0;
834 gator_monotonic_started = gator_get_time();
835
836 marshal_summary(timestamp, uptime, gator_monotonic_started, uname_buf);
837 preempt_enable();
838}
839
840int gator_events_install(struct gator_interface *interface)
841{
842 list_add_tail(&interface->list, &gator_events);
843
844 return 0;
845}
846
847int gator_events_get_key(void)
848{
849 // key 0 is reserved as a timestamp
850 // key 1 is reserved as the marker for thread specific counters
851 // Odd keys are assigned by the driver, even keys by the daemon
852 static int key = 3;
853
854 const int ret = key;
855 key += 2;
856 return ret;
857}
858
859static int gator_init(void)
860{
861 int i;
862
863 calc_first_cluster_size();
864
865 // events sources
866 for (i = 0; i < ARRAY_SIZE(gator_events_list); i++)
867 if (gator_events_list[i])
868 gator_events_list[i]();
869
870 gator_trace_sched_init();
871 gator_trace_power_init();
872
873 return 0;
874}
875
876static void gator_exit(void)
877{
878 struct gator_interface *gi;
879
880 list_for_each_entry(gi, &gator_events, list)
881 if (gi->shutdown)
882 gi->shutdown();
883}
884
885static int gator_start(void)
886{
887 unsigned long cpu, i;
888 struct gator_interface *gi;
889
890 gator_buffer_wake_run = true;
891 if (IS_ERR(gator_buffer_wake_thread = kthread_run(gator_buffer_wake_func, NULL, "gator_bwake"))) {
892 goto bwake_failure;
893 }
894
895 if (gator_migrate_start())
896 goto migrate_failure;
897
898 // Initialize the buffer with the frame type and core
899 for_each_present_cpu(cpu) {
900 for (i = 0; i < NUM_GATOR_BUFS; i++) {
901 marshal_frame(cpu, i);
902 }
903 per_cpu(last_timestamp, cpu) = 0;
904 }
905 printed_monotonic_warning = false;
906
907 // Capture the start time
908 gator_summary();
909
910 // start all events
911 list_for_each_entry(gi, &gator_events, list) {
912 if (gi->start && gi->start() != 0) {
913 struct list_head *ptr = gi->list.prev;
914
915 while (ptr != &gator_events) {
916 gi = list_entry(ptr, struct gator_interface, list);
917
918 if (gi->stop)
919 gi->stop();
920
921 ptr = ptr->prev;
922 }
923 goto events_failure;
924 }
925 }
926
927 // cookies shall be initialized before trace_sched_start() and gator_timer_start()
928 if (cookies_initialize())
929 goto cookies_failure;
930 if (gator_annotate_start())
931 goto annotate_failure;
932 if (gator_trace_sched_start())
933 goto sched_failure;
934 if (gator_trace_power_start())
935 goto power_failure;
936 if (gator_trace_gpu_start())
937 goto gpu_failure;
938 if (gator_timer_start(gator_timer_count))
939 goto timer_failure;
940 if (gator_notifier_start())
941 goto notifier_failure;
942
943 return 0;
944
945notifier_failure:
946 gator_timer_stop();
947timer_failure:
948 gator_trace_gpu_stop();
949gpu_failure:
950 gator_trace_power_stop();
951power_failure:
952 gator_trace_sched_stop();
953sched_failure:
954 gator_annotate_stop();
955annotate_failure:
956 cookies_release();
957cookies_failure:
958 // stop all events
959 list_for_each_entry(gi, &gator_events, list)
960 if (gi->stop)
961 gi->stop();
962events_failure:
963 gator_migrate_stop();
964migrate_failure:
965 gator_buffer_wake_run = false;
966 up(&gator_buffer_wake_sem);
967 gator_buffer_wake_thread = NULL;
968bwake_failure:
969
970 return -1;
971}
972
973static void gator_stop(void)
974{
975 struct gator_interface *gi;
976
977 gator_annotate_stop();
978 gator_trace_sched_stop();
979 gator_trace_power_stop();
980 gator_trace_gpu_stop();
981
982 // stop all interrupt callback reads before tearing down other interfaces
983 gator_notifier_stop(); // should be called before gator_timer_stop to avoid re-enabling the hrtimer after it has been offlined
984 gator_timer_stop();
985
986 // stop all events
987 list_for_each_entry(gi, &gator_events, list)
988 if (gi->stop)
989 gi->stop();
990
991 gator_migrate_stop();
992
993 gator_buffer_wake_run = false;
994 up(&gator_buffer_wake_sem);
995 gator_buffer_wake_thread = NULL;
996}
997
998/******************************************************************************
999 * Filesystem
1000 ******************************************************************************/
1001/* fopen("buffer") */
1002static int gator_op_setup(void)
1003{
1004 int err = 0;
1005 int cpu, i;
1006
1007 mutex_lock(&start_mutex);
1008
1009 gator_buffer_size[SUMMARY_BUF] = SUMMARY_BUFFER_SIZE;
1010 gator_buffer_mask[SUMMARY_BUF] = SUMMARY_BUFFER_SIZE - 1;
1011
1012 gator_buffer_size[BACKTRACE_BUF] = BACKTRACE_BUFFER_SIZE;
1013 gator_buffer_mask[BACKTRACE_BUF] = BACKTRACE_BUFFER_SIZE - 1;
1014
1015 gator_buffer_size[NAME_BUF] = NAME_BUFFER_SIZE;
1016 gator_buffer_mask[NAME_BUF] = NAME_BUFFER_SIZE - 1;
1017
1018 gator_buffer_size[COUNTER_BUF] = COUNTER_BUFFER_SIZE;
1019 gator_buffer_mask[COUNTER_BUF] = COUNTER_BUFFER_SIZE - 1;
1020
1021 gator_buffer_size[BLOCK_COUNTER_BUF] = BLOCK_COUNTER_BUFFER_SIZE;
1022 gator_buffer_mask[BLOCK_COUNTER_BUF] = BLOCK_COUNTER_BUFFER_SIZE - 1;
1023
1024 gator_buffer_size[ANNOTATE_BUF] = ANNOTATE_BUFFER_SIZE;
1025 gator_buffer_mask[ANNOTATE_BUF] = ANNOTATE_BUFFER_SIZE - 1;
1026
1027 gator_buffer_size[SCHED_TRACE_BUF] = SCHED_TRACE_BUFFER_SIZE;
1028 gator_buffer_mask[SCHED_TRACE_BUF] = SCHED_TRACE_BUFFER_SIZE - 1;
1029
1030 gator_buffer_size[IDLE_BUF] = IDLE_BUFFER_SIZE;
1031 gator_buffer_mask[IDLE_BUF] = IDLE_BUFFER_SIZE - 1;
1032
1033 gator_buffer_size[ACTIVITY_BUF] = ACTIVITY_BUFFER_SIZE;
1034 gator_buffer_mask[ACTIVITY_BUF] = ACTIVITY_BUFFER_SIZE - 1;
1035
1036 // Initialize percpu per buffer variables
1037 for (i = 0; i < NUM_GATOR_BUFS; i++) {
1038 // Verify buffers are a power of 2
1039 if (gator_buffer_size[i] & (gator_buffer_size[i] - 1)) {
1040 err = -ENOEXEC;
1041 goto setup_error;
1042 }
1043
1044 for_each_present_cpu(cpu) {
1045 per_cpu(gator_buffer_read, cpu)[i] = 0;
1046 per_cpu(gator_buffer_write, cpu)[i] = 0;
1047 per_cpu(gator_buffer_commit, cpu)[i] = 0;
1048 per_cpu(buffer_space_available, cpu)[i] = true;
1049 per_cpu(gator_buffer_commit_time, cpu) = gator_live_rate;
1050
1051 // Annotation is a special case that only uses a single buffer
1052 if (cpu > 0 && i == ANNOTATE_BUF) {
1053 per_cpu(gator_buffer, cpu)[i] = NULL;
1054 continue;
1055 }
1056
1057 per_cpu(gator_buffer, cpu)[i] = vmalloc(gator_buffer_size[i]);
1058 if (!per_cpu(gator_buffer, cpu)[i]) {
1059 err = -ENOMEM;
1060 goto setup_error;
1061 }
1062 }
1063 }
1064
1065setup_error:
1066 mutex_unlock(&start_mutex);
1067 return err;
1068}
1069
1070/* Actually start profiling (echo 1>/dev/gator/enable) */
1071static int gator_op_start(void)
1072{
1073 int err = 0;
1074
1075 mutex_lock(&start_mutex);
1076
1077 if (gator_started || gator_start())
1078 err = -EINVAL;
1079 else
1080 gator_started = 1;
1081
1082 mutex_unlock(&start_mutex);
1083
1084 return err;
1085}
1086
1087/* echo 0>/dev/gator/enable */
1088static void gator_op_stop(void)
1089{
1090 mutex_lock(&start_mutex);
1091
1092 if (gator_started) {
1093 gator_stop();
1094
1095 mutex_lock(&gator_buffer_mutex);
1096
1097 gator_started = 0;
1098 gator_monotonic_started = 0;
1099 cookies_release();
1100 wake_up(&gator_buffer_wait);
1101
1102 mutex_unlock(&gator_buffer_mutex);
1103 }
1104
1105 mutex_unlock(&start_mutex);
1106}
1107
1108static void gator_shutdown(void)
1109{
1110 int cpu, i;
1111
1112 mutex_lock(&start_mutex);
1113
1114 for_each_present_cpu(cpu) {
1115 mutex_lock(&gator_buffer_mutex);
1116 for (i = 0; i < NUM_GATOR_BUFS; i++) {
1117 vfree(per_cpu(gator_buffer, cpu)[i]);
1118 per_cpu(gator_buffer, cpu)[i] = NULL;
1119 per_cpu(gator_buffer_read, cpu)[i] = 0;
1120 per_cpu(gator_buffer_write, cpu)[i] = 0;
1121 per_cpu(gator_buffer_commit, cpu)[i] = 0;
1122 per_cpu(buffer_space_available, cpu)[i] = true;
1123 per_cpu(gator_buffer_commit_time, cpu) = 0;
1124 }
1125 mutex_unlock(&gator_buffer_mutex);
1126 }
1127
1128 memset(&sent_core_name, 0, sizeof(sent_core_name));
1129
1130 mutex_unlock(&start_mutex);
1131}
1132
1133static int gator_set_backtrace(unsigned long val)
1134{
1135 int err = 0;
1136
1137 mutex_lock(&start_mutex);
1138
1139 if (gator_started)
1140 err = -EBUSY;
1141 else
1142 gator_backtrace_depth = val;
1143
1144 mutex_unlock(&start_mutex);
1145
1146 return err;
1147}
1148
1149static ssize_t enable_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
1150{
1151 return gatorfs_ulong_to_user(gator_started, buf, count, offset);
1152}
1153
1154static ssize_t enable_write(struct file *file, char const __user *buf, size_t count, loff_t *offset)
1155{
1156 unsigned long val;
1157 int retval;
1158
1159 if (*offset)
1160 return -EINVAL;
1161
1162 retval = gatorfs_ulong_from_user(&val, buf, count);
1163 if (retval)
1164 return retval;
1165
1166 if (val)
1167 retval = gator_op_start();
1168 else
1169 gator_op_stop();
1170
1171 if (retval)
1172 return retval;
1173 return count;
1174}
1175
1176static const struct file_operations enable_fops = {
1177 .read = enable_read,
1178 .write = enable_write,
1179};
1180
1181static int userspace_buffer_open(struct inode *inode, struct file *file)
1182{
1183 int err = -EPERM;
1184
1185 if (!capable(CAP_SYS_ADMIN))
1186 return -EPERM;
1187
1188 if (test_and_set_bit_lock(0, &gator_buffer_opened))
1189 return -EBUSY;
1190
1191 if ((err = gator_op_setup()))
1192 goto fail;
1193
1194 /* NB: the actual start happens from userspace
1195 * echo 1 >/dev/gator/enable
1196 */
1197
1198 return 0;
1199
1200fail:
1201 __clear_bit_unlock(0, &gator_buffer_opened);
1202 return err;
1203}
1204
1205static int userspace_buffer_release(struct inode *inode, struct file *file)
1206{
1207 gator_op_stop();
1208 gator_shutdown();
1209 __clear_bit_unlock(0, &gator_buffer_opened);
1210 return 0;
1211}
1212
1213static ssize_t userspace_buffer_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
1214{
1215 int commit, length1, length2, read;
1216 char *buffer1;
1217 char *buffer2;
1218 int cpu, buftype;
1219 int written = 0;
1220
1221 // ensure there is enough space for a whole frame
1222 if (count < userspace_buffer_size || *offset) {
1223 return -EINVAL;
1224 }
1225
1226 // sleep until the condition is true or a signal is received
1227 // the condition is checked each time gator_buffer_wait is woken up
1228 wait_event_interruptible(gator_buffer_wait, buffer_commit_ready(&cpu, &buftype) || !gator_started);
1229
1230 if (signal_pending(current)) {
1231 return -EINTR;
1232 }
1233
1234 if (buftype == -1 || cpu == -1) {
1235 return 0;
1236 }
1237
1238 mutex_lock(&gator_buffer_mutex);
1239
1240 do {
1241 read = per_cpu(gator_buffer_read, cpu)[buftype];
1242 commit = per_cpu(gator_buffer_commit, cpu)[buftype];
1243
1244 // May happen if the buffer is freed during pending reads.
1245 if (!per_cpu(gator_buffer, cpu)[buftype]) {
1246 break;
1247 }
1248
1249 // determine the size of two halves
1250 length1 = commit - read;
1251 length2 = 0;
1252 buffer1 = &(per_cpu(gator_buffer, cpu)[buftype][read]);
1253 buffer2 = &(per_cpu(gator_buffer, cpu)[buftype][0]);
1254 if (length1 < 0) {
1255 length1 = gator_buffer_size[buftype] - read;
1256 length2 = commit;
1257 }
1258
1259 if (length1 + length2 > count - written) {
1260 break;
1261 }
1262
1263 // start, middle or end
1264 if (length1 > 0 && copy_to_user(&buf[written], buffer1, length1)) {
1265 break;
1266 }
1267
1268 // possible wrap around
1269 if (length2 > 0 && copy_to_user(&buf[written + length1], buffer2, length2)) {
1270 break;
1271 }
1272
1273 per_cpu(gator_buffer_read, cpu)[buftype] = commit;
1274 written += length1 + length2;
1275
1276 // Wake up annotate_write if more space is available
1277 if (buftype == ANNOTATE_BUF) {
1278 wake_up(&gator_annotate_wait);
1279 }
1280 } while (buffer_commit_ready(&cpu, &buftype));
1281
1282 mutex_unlock(&gator_buffer_mutex);
1283
1284 // kick just in case we've lost an SMP event
1285 wake_up(&gator_buffer_wait);
1286
1287 return written > 0 ? written : -EFAULT;
1288}
1289
1290static const struct file_operations gator_event_buffer_fops = {
1291 .open = userspace_buffer_open,
1292 .release = userspace_buffer_release,
1293 .read = userspace_buffer_read,
1294};
1295
1296static ssize_t depth_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
1297{
1298 return gatorfs_ulong_to_user(gator_backtrace_depth, buf, count, offset);
1299}
1300
1301static ssize_t depth_write(struct file *file, char const __user *buf, size_t count, loff_t *offset)
1302{
1303 unsigned long val;
1304 int retval;
1305
1306 if (*offset)
1307 return -EINVAL;
1308
1309 retval = gatorfs_ulong_from_user(&val, buf, count);
1310 if (retval)
1311 return retval;
1312
1313 retval = gator_set_backtrace(val);
1314
1315 if (retval)
1316 return retval;
1317 return count;
1318}
1319
1320static const struct file_operations depth_fops = {
1321 .read = depth_read,
1322 .write = depth_write
1323};
1324
1325static void gator_op_create_files(struct super_block *sb, struct dentry *root)
1326{
1327 struct dentry *dir;
1328 struct gator_interface *gi;
1329 int cpu;
1330
1331 /* reinitialize default values */
1332 gator_cpu_cores = 0;
1333 for_each_present_cpu(cpu) {
1334 gator_cpu_cores++;
1335 }
1336 userspace_buffer_size = BACKTRACE_BUFFER_SIZE;
1337 gator_response_type = 1;
1338 gator_live_rate = 0;
1339
1340 gatorfs_create_file(sb, root, "enable", &enable_fops);
1341 gatorfs_create_file(sb, root, "buffer", &gator_event_buffer_fops);
1342 gatorfs_create_file(sb, root, "backtrace_depth", &depth_fops);
1343 gatorfs_create_ro_ulong(sb, root, "cpu_cores", &gator_cpu_cores);
1344 gatorfs_create_ro_ulong(sb, root, "buffer_size", &userspace_buffer_size);
1345 gatorfs_create_ulong(sb, root, "tick", &gator_timer_count);
1346 gatorfs_create_ulong(sb, root, "response_type", &gator_response_type);
1347 gatorfs_create_ro_ulong(sb, root, "version", &gator_protocol_version);
1348 gatorfs_create_ro_u64(sb, root, "started", &gator_monotonic_started);
1349 gatorfs_create_u64(sb, root, "live_rate", &gator_live_rate);
1350
1351 // Annotate interface
1352 gator_annotate_create_files(sb, root);
1353
1354 // Linux Events
1355 dir = gatorfs_mkdir(sb, root, "events");
1356 list_for_each_entry(gi, &gator_events, list)
1357 if (gi->create_files)
1358 gi->create_files(sb, dir);
1359
1360 // Sched Events
1361 sched_trace_create_files(sb, dir);
1362
1363 // Power interface
1364 gator_trace_power_create_files(sb, dir);
1365}
1366
1367/******************************************************************************
1368 * Module
1369 ******************************************************************************/
1370
1371#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
1372
1373#define GATOR_TRACEPOINTS \
1374 GATOR_HANDLE_TRACEPOINT(block_rq_complete); \
1375 GATOR_HANDLE_TRACEPOINT(cpu_frequency); \
1376 GATOR_HANDLE_TRACEPOINT(cpu_idle); \
1377 GATOR_HANDLE_TRACEPOINT(cpu_migrate_begin); \
1378 GATOR_HANDLE_TRACEPOINT(cpu_migrate_current); \
1379 GATOR_HANDLE_TRACEPOINT(cpu_migrate_finish); \
1380 GATOR_HANDLE_TRACEPOINT(irq_handler_exit); \
1381 GATOR_HANDLE_TRACEPOINT(mali_hw_counter); \
1382 GATOR_HANDLE_TRACEPOINT(mali_job_slots_event); \
1383 GATOR_HANDLE_TRACEPOINT(mali_mmu_as_in_use); \
1384 GATOR_HANDLE_TRACEPOINT(mali_mmu_as_released); \
1385 GATOR_HANDLE_TRACEPOINT(mali_page_fault_insert_pages); \
1386 GATOR_HANDLE_TRACEPOINT(mali_pm_status); \
1387 GATOR_HANDLE_TRACEPOINT(mali_sw_counter); \
1388 GATOR_HANDLE_TRACEPOINT(mali_sw_counters); \
1389 GATOR_HANDLE_TRACEPOINT(mali_timeline_event); \
1390 GATOR_HANDLE_TRACEPOINT(mali_total_alloc_pages_change); \
1391 GATOR_HANDLE_TRACEPOINT(mm_page_alloc); \
1392 GATOR_HANDLE_TRACEPOINT(mm_page_free); \
1393 GATOR_HANDLE_TRACEPOINT(mm_page_free_batched); \
1394 GATOR_HANDLE_TRACEPOINT(sched_process_exec); \
1395 GATOR_HANDLE_TRACEPOINT(sched_process_fork); \
1396 GATOR_HANDLE_TRACEPOINT(sched_process_free); \
1397 GATOR_HANDLE_TRACEPOINT(sched_switch); \
1398 GATOR_HANDLE_TRACEPOINT(softirq_exit); \
1399
1400#define GATOR_HANDLE_TRACEPOINT(probe_name) \
1401 struct tracepoint *gator_tracepoint_##probe_name
1402GATOR_TRACEPOINTS;
1403#undef GATOR_HANDLE_TRACEPOINT
1404
1405static void gator_fct(struct tracepoint *tp, void *priv)
1406{
1407#define GATOR_HANDLE_TRACEPOINT(probe_name) \
1408 if (strcmp(tp->name, #probe_name) == 0) { \
1409 gator_tracepoint_##probe_name = tp; \
1410 return; \
1411 }
1412GATOR_TRACEPOINTS;
1413#undef GATOR_HANDLE_TRACEPOINT
1414}
1415
1416#else
1417
1418#define for_each_kernel_tracepoint(fct, priv)
1419
1420#endif
1421
1422static int __init gator_module_init(void)
1423{
1424 for_each_kernel_tracepoint(gator_fct, NULL);
1425
1426 if (gatorfs_register()) {
1427 return -1;
1428 }
1429
1430 if (gator_init()) {
1431 gatorfs_unregister();
1432 return -1;
1433 }
1434
1435 setup_timer(&gator_buffer_wake_up_timer, gator_buffer_wake_up, 0);
1436
1437 // Initialize the list of cpuids
1438 memset(gator_cpuids, -1, sizeof(gator_cpuids));
1439 on_each_cpu(gator_read_cpuid, NULL, 1);
1440
1441 return 0;
1442}
1443
1444static void __exit gator_module_exit(void)
1445{
1446 del_timer_sync(&gator_buffer_wake_up_timer);
1447 tracepoint_synchronize_unregister();
1448 gator_exit();
1449 gatorfs_unregister();
1450}
1451
1452module_init(gator_module_init);
1453module_exit(gator_module_exit);
1454
1455MODULE_LICENSE("GPL");
1456MODULE_AUTHOR("ARM Ltd");
1457MODULE_DESCRIPTION("Gator system profiler");
1458#define STRIFY2(ARG) #ARG
1459#define STRIFY(ARG) STRIFY2(ARG)
1460MODULE_VERSION(STRIFY(PROTOCOL_VERSION));
diff --git a/drivers/gator/gator_marshaling.c b/drivers/gator/gator_marshaling.c
new file mode 100644
index 00000000000..97b4ae6f9d4
--- /dev/null
+++ b/drivers/gator/gator_marshaling.c
@@ -0,0 +1,362 @@
1/**
2 * Copyright (C) ARM Limited 2012-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10#define NEWLINE_CANARY \
11 /* Unix */ \
12 "1\n" \
13 /* Windows */ \
14 "2\r\n" \
15 /* Mac OS */ \
16 "3\r" \
17 /* RISC OS */ \
18 "4\n\r" \
19 /* Add another character so the length isn't 0x0a bytes */ \
20 "5"
21
22#ifdef MALI_SUPPORT
23#include "gator_events_mali_common.h"
24#endif
25
26static void marshal_summary(long long timestamp, long long uptime, long long monotonic_delta, const char * uname)
27{
28 unsigned long flags;
29 int cpu = 0;
30
31 local_irq_save(flags);
32 gator_buffer_write_packed_int(cpu, SUMMARY_BUF, MESSAGE_SUMMARY);
33 gator_buffer_write_string(cpu, SUMMARY_BUF, NEWLINE_CANARY);
34 gator_buffer_write_packed_int64(cpu, SUMMARY_BUF, timestamp);
35 gator_buffer_write_packed_int64(cpu, SUMMARY_BUF, uptime);
36 gator_buffer_write_packed_int64(cpu, SUMMARY_BUF, monotonic_delta);
37 gator_buffer_write_string(cpu, SUMMARY_BUF, "uname");
38 gator_buffer_write_string(cpu, SUMMARY_BUF, uname);
39#if GATOR_IKS_SUPPORT
40 gator_buffer_write_string(cpu, SUMMARY_BUF, "iks");
41 gator_buffer_write_string(cpu, SUMMARY_BUF, "");
42#endif
43 // Let Streamline know which GPU is used so that it can label the GPU Activity appropriately. This is a temporary fix, to be improved in a future release.
44#ifdef MALI_SUPPORT
45 gator_buffer_write_string(cpu, SUMMARY_BUF, "mali_type");
46#if (MALI_SUPPORT == MALI_4xx)
47 gator_buffer_write_string(cpu, SUMMARY_BUF, "4xx");
48#elif (MALI_SUPPORT == MALI_T6xx)
49 gator_buffer_write_string(cpu, SUMMARY_BUF, "6xx");
50#else
51 gator_buffer_write_string(cpu, SUMMARY_BUF, "unknown");
52#endif
53#endif
54 gator_buffer_write_string(cpu, SUMMARY_BUF, "");
55 // Commit the buffer now so it can be one of the first frames read by Streamline
56 local_irq_restore(flags);
57 gator_commit_buffer(cpu, SUMMARY_BUF, gator_get_time());
58}
59
60static bool marshal_cookie_header(const char *text)
61{
62 int cpu = get_physical_cpu();
63 return buffer_check_space(cpu, NAME_BUF, strlen(text) + 3 * MAXSIZE_PACK32);
64}
65
66static void marshal_cookie(int cookie, const char *text)
67{
68 int cpu = get_physical_cpu();
69 // buffer_check_space already called by marshal_cookie_header
70 gator_buffer_write_packed_int(cpu, NAME_BUF, MESSAGE_COOKIE);
71 gator_buffer_write_packed_int(cpu, NAME_BUF, cookie);
72 gator_buffer_write_string(cpu, NAME_BUF, text);
73 buffer_check(cpu, NAME_BUF, gator_get_time());
74}
75
76static void marshal_thread_name(int pid, char *name)
77{
78 unsigned long flags, cpu;
79 u64 time;
80 local_irq_save(flags);
81 cpu = get_physical_cpu();
82 time = gator_get_time();
83 if (buffer_check_space(cpu, NAME_BUF, TASK_COMM_LEN + 3 * MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
84 gator_buffer_write_packed_int(cpu, NAME_BUF, MESSAGE_THREAD_NAME);
85 gator_buffer_write_packed_int64(cpu, NAME_BUF, time);
86 gator_buffer_write_packed_int(cpu, NAME_BUF, pid);
87 gator_buffer_write_string(cpu, NAME_BUF, name);
88 }
89 local_irq_restore(flags);
90 buffer_check(cpu, NAME_BUF, time);
91}
92
93static void marshal_link(int cookie, int tgid, int pid)
94{
95 unsigned long cpu = get_physical_cpu(), flags;
96 u64 time;
97
98 local_irq_save(flags);
99 time = gator_get_time();
100 if (buffer_check_space(cpu, NAME_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32)) {
101 gator_buffer_write_packed_int(cpu, NAME_BUF, MESSAGE_LINK);
102 gator_buffer_write_packed_int64(cpu, NAME_BUF, time);
103 gator_buffer_write_packed_int(cpu, NAME_BUF, cookie);
104 gator_buffer_write_packed_int(cpu, NAME_BUF, tgid);
105 gator_buffer_write_packed_int(cpu, NAME_BUF, pid);
106 }
107 local_irq_restore(flags);
108 // Check and commit; commit is set to occur once buffer is 3/4 full
109 buffer_check(cpu, NAME_BUF, time);
110}
111
112static bool marshal_backtrace_header(int exec_cookie, int tgid, int pid, u64 time)
113{
114 int cpu = get_physical_cpu();
115 if (!buffer_check_space(cpu, BACKTRACE_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32 + gator_backtrace_depth * 2 * MAXSIZE_PACK32)) {
116 // Check and commit; commit is set to occur once buffer is 3/4 full
117 buffer_check(cpu, BACKTRACE_BUF, time);
118
119 return false;
120 }
121
122 gator_buffer_write_packed_int64(cpu, BACKTRACE_BUF, time);
123 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, exec_cookie);
124 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, tgid);
125 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, pid);
126
127 return true;
128}
129
130static void marshal_backtrace(unsigned long address, int cookie, int in_kernel)
131{
132 int cpu = get_physical_cpu();
133 if (cookie == 0 && !in_kernel) {
134 cookie = UNRESOLVED_COOKIE;
135 }
136 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, cookie);
137 gator_buffer_write_packed_int64(cpu, BACKTRACE_BUF, address);
138}
139
140static void marshal_backtrace_footer(u64 time)
141{
142 int cpu = get_physical_cpu();
143 gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, MESSAGE_END_BACKTRACE);
144
145 // Check and commit; commit is set to occur once buffer is 3/4 full
146 buffer_check(cpu, BACKTRACE_BUF, time);
147}
148
149static bool marshal_event_header(u64 time)
150{
151 unsigned long flags, cpu = get_physical_cpu();
152 bool retval = false;
153
154 local_irq_save(flags);
155 if (buffer_check_space(cpu, BLOCK_COUNTER_BUF, MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
156 gator_buffer_write_packed_int(cpu, BLOCK_COUNTER_BUF, 0); // key of zero indicates a timestamp
157 gator_buffer_write_packed_int64(cpu, BLOCK_COUNTER_BUF, time);
158 retval = true;
159 }
160 local_irq_restore(flags);
161
162 return retval;
163}
164
165static void marshal_event(int len, int *buffer)
166{
167 unsigned long i, flags, cpu = get_physical_cpu();
168
169 if (len <= 0)
170 return;
171
172 // length must be even since all data is a (key, value) pair
173 if (len & 0x1) {
174 pr_err("gator: invalid counter data detected and discarded");
175 return;
176 }
177
178 // events must be written in key,value pairs
179 local_irq_save(flags);
180 for (i = 0; i < len; i += 2) {
181 if (!buffer_check_space(cpu, BLOCK_COUNTER_BUF, 2 * MAXSIZE_PACK32)) {
182 break;
183 }
184 gator_buffer_write_packed_int(cpu, BLOCK_COUNTER_BUF, buffer[i]);
185 gator_buffer_write_packed_int(cpu, BLOCK_COUNTER_BUF, buffer[i + 1]);
186 }
187 local_irq_restore(flags);
188}
189
190static void marshal_event64(int len, long long *buffer64)
191{
192 unsigned long i, flags, cpu = get_physical_cpu();
193
194 if (len <= 0)
195 return;
196
197 // length must be even since all data is a (key, value) pair
198 if (len & 0x1) {
199 pr_err("gator: invalid counter data detected and discarded");
200 return;
201 }
202
203 // events must be written in key,value pairs
204 local_irq_save(flags);
205 for (i = 0; i < len; i += 2) {
206 if (!buffer_check_space(cpu, BLOCK_COUNTER_BUF, 2 * MAXSIZE_PACK64)) {
207 break;
208 }
209 gator_buffer_write_packed_int64(cpu, BLOCK_COUNTER_BUF, buffer64[i]);
210 gator_buffer_write_packed_int64(cpu, BLOCK_COUNTER_BUF, buffer64[i + 1]);
211 }
212 local_irq_restore(flags);
213}
214
215#if GATOR_CPU_FREQ_SUPPORT
216static void marshal_event_single(int core, int key, int value)
217{
218 unsigned long flags, cpu;
219 u64 time;
220
221 local_irq_save(flags);
222 cpu = get_physical_cpu();
223 time = gator_get_time();
224 if (buffer_check_space(cpu, COUNTER_BUF, MAXSIZE_PACK64 + 3 * MAXSIZE_PACK32)) {
225 gator_buffer_write_packed_int64(cpu, COUNTER_BUF, time);
226 gator_buffer_write_packed_int(cpu, COUNTER_BUF, core);
227 gator_buffer_write_packed_int(cpu, COUNTER_BUF, key);
228 gator_buffer_write_packed_int(cpu, COUNTER_BUF, value);
229 }
230 local_irq_restore(flags);
231 // Check and commit; commit is set to occur once buffer is 3/4 full
232 buffer_check(cpu, COUNTER_BUF, time);
233}
234
235static void marshal_event_single64(int core, int key, long long value)
236{
237 unsigned long flags, cpu;
238 u64 time;
239
240 local_irq_save(flags);
241 cpu = get_physical_cpu();
242 time = gator_get_time();
243 if (buffer_check_space(cpu, COUNTER_BUF, 2 * MAXSIZE_PACK64 + 2 * MAXSIZE_PACK32)) {
244 gator_buffer_write_packed_int64(cpu, COUNTER_BUF, time);
245 gator_buffer_write_packed_int(cpu, COUNTER_BUF, core);
246 gator_buffer_write_packed_int(cpu, COUNTER_BUF, key);
247 gator_buffer_write_packed_int64(cpu, COUNTER_BUF, value);
248 }
249 local_irq_restore(flags);
250 // Check and commit; commit is set to occur once buffer is 3/4 full
251 buffer_check(cpu, COUNTER_BUF, time);
252}
253#endif
254
255static void marshal_sched_trace_switch(int pid, int state)
256{
257 unsigned long cpu = get_physical_cpu(), flags;
258 u64 time;
259
260 if (!per_cpu(gator_buffer, cpu)[SCHED_TRACE_BUF])
261 return;
262
263 local_irq_save(flags);
264 time = gator_get_time();
265 if (buffer_check_space(cpu, SCHED_TRACE_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32)) {
266 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, MESSAGE_SCHED_SWITCH);
267 gator_buffer_write_packed_int64(cpu, SCHED_TRACE_BUF, time);
268 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, pid);
269 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, state);
270 }
271 local_irq_restore(flags);
272 // Check and commit; commit is set to occur once buffer is 3/4 full
273 buffer_check(cpu, SCHED_TRACE_BUF, time);
274}
275
276static void marshal_sched_trace_exit(int tgid, int pid)
277{
278 unsigned long cpu = get_physical_cpu(), flags;
279 u64 time;
280
281 if (!per_cpu(gator_buffer, cpu)[SCHED_TRACE_BUF])
282 return;
283
284 local_irq_save(flags);
285 time = gator_get_time();
286 if (buffer_check_space(cpu, SCHED_TRACE_BUF, MAXSIZE_PACK64 + 2 * MAXSIZE_PACK32)) {
287 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, MESSAGE_SCHED_EXIT);
288 gator_buffer_write_packed_int64(cpu, SCHED_TRACE_BUF, time);
289 gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, pid);
290 }
291 local_irq_restore(flags);
292 // Check and commit; commit is set to occur once buffer is 3/4 full
293 buffer_check(cpu, SCHED_TRACE_BUF, time);
294}
295
296#if GATOR_CPU_FREQ_SUPPORT
297static void marshal_idle(int core, int state)
298{
299 unsigned long flags, cpu;
300 u64 time;
301
302 local_irq_save(flags);
303 cpu = get_physical_cpu();
304 time = gator_get_time();
305 if (buffer_check_space(cpu, IDLE_BUF, MAXSIZE_PACK64 + 2 * MAXSIZE_PACK32)) {
306 gator_buffer_write_packed_int(cpu, IDLE_BUF, state);
307 gator_buffer_write_packed_int64(cpu, IDLE_BUF, time);
308 gator_buffer_write_packed_int(cpu, IDLE_BUF, core);
309 }
310 local_irq_restore(flags);
311 // Check and commit; commit is set to occur once buffer is 3/4 full
312 buffer_check(cpu, IDLE_BUF, time);
313}
314#endif
315
316#if defined(__arm__) || defined(__aarch64__)
317static void marshal_core_name(const int core, const int cpuid, const char *name)
318{
319 int cpu = get_physical_cpu();
320 unsigned long flags;
321 local_irq_save(flags);
322 if (buffer_check_space(cpu, SUMMARY_BUF, MAXSIZE_PACK32 + MAXSIZE_CORE_NAME)) {
323 gator_buffer_write_packed_int(cpu, SUMMARY_BUF, MESSAGE_CORE_NAME);
324 gator_buffer_write_packed_int(cpu, SUMMARY_BUF, core);
325 gator_buffer_write_packed_int(cpu, SUMMARY_BUF, cpuid);
326 gator_buffer_write_string(cpu, SUMMARY_BUF, name);
327 }
328 // Commit core names now so that they can show up in live
329 local_irq_restore(flags);
330 gator_commit_buffer(cpu, SUMMARY_BUF, gator_get_time());
331}
332#endif
333
334static void marshal_activity_switch(int core, int key, int activity, int pid, int state)
335{
336 unsigned long cpu = get_physical_cpu(), flags;
337 u64 time;
338
339 if (!per_cpu(gator_buffer, cpu)[ACTIVITY_BUF])
340 return;
341
342 local_irq_save(flags);
343 time = gator_get_time();
344 if (buffer_check_space(cpu, ACTIVITY_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32)) {
345 gator_buffer_write_packed_int(cpu, ACTIVITY_BUF, MESSAGE_SWITCH);
346 gator_buffer_write_packed_int64(cpu, ACTIVITY_BUF, time);
347 gator_buffer_write_packed_int(cpu, ACTIVITY_BUF, core);
348 gator_buffer_write_packed_int(cpu, ACTIVITY_BUF, key);
349 gator_buffer_write_packed_int(cpu, ACTIVITY_BUF, activity);
350 gator_buffer_write_packed_int(cpu, ACTIVITY_BUF, pid);
351 gator_buffer_write_packed_int(cpu, ACTIVITY_BUF, state);
352 }
353 local_irq_restore(flags);
354 // Check and commit; commit is set to occur once buffer is 3/4 full
355 buffer_check(cpu, ACTIVITY_BUF, time);
356}
357
358void gator_marshal_activity_switch(int core, int key, int activity, int pid)
359{
360 // state is reserved for cpu use only
361 marshal_activity_switch(core, key, activity, pid, 0);
362}
diff --git a/drivers/gator/gator_trace_gpu.c b/drivers/gator/gator_trace_gpu.c
new file mode 100644
index 00000000000..a8b9e7d61ec
--- /dev/null
+++ b/drivers/gator/gator_trace_gpu.c
@@ -0,0 +1,333 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "gator.h"
10
11#include <linux/slab.h>
12#include <linux/module.h>
13#include <linux/time.h>
14#include <linux/math64.h>
15
16#ifdef MALI_SUPPORT
17#ifdef MALI_DIR_MIDGARD
18/* New DDK Directory structure with kernel/drivers/gpu/arm/midgard*/
19#include "mali_linux_trace.h"
20#else
21/* Old DDK Directory structure with kernel/drivers/gpu/arm/t6xx*/
22#include "linux/mali_linux_trace.h"
23#endif
24#endif
25
26/*
27 * Taken from MALI_PROFILING_EVENT_TYPE_* items in Mali DDK.
28 */
29#define EVENT_TYPE_SINGLE 0
30#define EVENT_TYPE_START 1
31#define EVENT_TYPE_STOP 2
32#define EVENT_TYPE_SUSPEND 3
33#define EVENT_TYPE_RESUME 4
34
35/* Note whether tracepoints have been registered */
36static int mali_timeline_trace_registered;
37static int mali_job_slots_trace_registered;
38
39enum {
40 GPU_UNIT_NONE = 0,
41 GPU_UNIT_VP,
42 GPU_UNIT_FP,
43 GPU_UNIT_CL,
44 NUMBER_OF_GPU_UNITS
45};
46
47#if defined(MALI_SUPPORT)
48
49struct mali_activity {
50 int core;
51 int key;
52 int count;
53 int last_activity;
54 int last_pid;
55};
56
57#define NUMBER_OF_GPU_CORES 16
58static struct mali_activity mali_activities[NUMBER_OF_GPU_UNITS*NUMBER_OF_GPU_CORES];
59static DEFINE_SPINLOCK(mali_activities_lock);
60
61/* Only one event should be running on a unit and core at a time (ie, a start
62 * event can only be followed by a stop and vice versa), but because the kernel
63 * only knows when a job is enqueued and not started, it is possible for a
64 * start1, start2, stop1, stop2. Change it back into start1, stop1, start2,
65 * stop2 by queueing up start2 and releasing it when stop1 is received.
66 */
67
68static int mali_activity_index(int core, int key)
69{
70 int i;
71
72 for (i = 0; i < ARRAY_SIZE(mali_activities); ++i) {
73 if ((mali_activities[i].core == core) && (mali_activities[i].key == key)) {
74 break;
75 }
76 if ((mali_activities[i].core == 0) && (mali_activities[i].key == 0)) {
77 mali_activities[i].core = core;
78 mali_activities[i].key = key;
79 break;
80 }
81 }
82 BUG_ON(i >= ARRAY_SIZE(mali_activities));
83
84 return i;
85}
86
87static void mali_activity_enqueue(int core, int key, int activity, int pid)
88{
89 int i;
90 int count;
91
92 spin_lock(&mali_activities_lock);
93 i = mali_activity_index(core, key);
94
95 count = mali_activities[i].count;
96 BUG_ON(count < 0);
97 ++mali_activities[i].count;
98 if (count) {
99 mali_activities[i].last_activity = activity;
100 mali_activities[i].last_pid = pid;
101 }
102 spin_unlock(&mali_activities_lock);
103
104 if (!count) {
105 gator_marshal_activity_switch(core, key, activity, pid);
106 }
107}
108
109static void mali_activity_stop(int core, int key)
110{
111 int i;
112 int count;
113 int last_activity = 0;
114 int last_pid = 0;
115
116 spin_lock(&mali_activities_lock);
117 i = mali_activity_index(core, key);
118
119 if (mali_activities[i].count == 0) {
120 spin_unlock(&mali_activities_lock);
121 return;
122 }
123 --mali_activities[i].count;
124 count = mali_activities[i].count;
125 if (count) {
126 last_activity = mali_activities[i].last_activity;
127 last_pid = mali_activities[i].last_pid;
128 }
129 spin_unlock(&mali_activities_lock);
130
131 gator_marshal_activity_switch(core, key, 0, 0);
132 if (count) {
133 gator_marshal_activity_switch(core, key, last_activity, last_pid);
134 }
135}
136
137void mali_activity_clear(mali_counter mali_activity[], size_t mali_activity_size)
138{
139 int activity;
140 int cores;
141 int core;
142
143 for (activity = 0; activity < mali_activity_size; ++activity) {
144 cores = mali_activity[activity].cores;
145 if (cores < 0) {
146 cores = 1;
147 }
148 for (core = 0; core < cores; ++core) {
149 if (mali_activity[activity].enabled) {
150 gator_marshal_activity_switch(core, mali_activity[activity].key, 0, 0);
151 }
152 }
153 }
154}
155
156#endif
157
158#if defined(MALI_SUPPORT) && (MALI_SUPPORT != MALI_T6xx)
159#include "gator_events_mali_4xx.h"
160
161/*
162 * Taken from MALI_PROFILING_EVENT_CHANNEL_* in Mali DDK.
163 */
164enum {
165 EVENT_CHANNEL_SOFTWARE = 0,
166 EVENT_CHANNEL_VP0 = 1,
167 EVENT_CHANNEL_FP0 = 5,
168 EVENT_CHANNEL_FP1,
169 EVENT_CHANNEL_FP2,
170 EVENT_CHANNEL_FP3,
171 EVENT_CHANNEL_FP4,
172 EVENT_CHANNEL_FP5,
173 EVENT_CHANNEL_FP6,
174 EVENT_CHANNEL_FP7,
175 EVENT_CHANNEL_GPU = 21
176};
177
178/**
179 * These events are applicable when the type MALI_PROFILING_EVENT_TYPE_SINGLE is used from the GPU channel
180 */
181enum {
182 EVENT_REASON_SINGLE_GPU_NONE = 0,
183 EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE = 1,
184};
185
186mali_counter mali_activity[2];
187
188GATOR_DEFINE_PROBE(mali_timeline_event, TP_PROTO(unsigned int event_id, unsigned int d0, unsigned int d1, unsigned int d2, unsigned int d3, unsigned int d4))
189{
190 unsigned int component, state;
191
192 // do as much work as possible before disabling interrupts
193 component = (event_id >> 16) & 0xFF; // component is an 8-bit field
194 state = (event_id >> 24) & 0xF; // state is a 4-bit field
195
196 switch (state) {
197 case EVENT_TYPE_START:
198 if (component == EVENT_CHANNEL_VP0) {
199 /* tgid = d0; pid = d1; */
200 if (mali_activity[1].enabled) {
201 mali_activity_enqueue(0, mali_activity[1].key, 1, d1);
202 }
203 } else if (component >= EVENT_CHANNEL_FP0 && component <= EVENT_CHANNEL_FP7) {
204 /* tgid = d0; pid = d1; */
205 if (mali_activity[0].enabled) {
206 mali_activity_enqueue(component - EVENT_CHANNEL_FP0, mali_activity[0].key, 1, d1);
207 }
208 }
209 break;
210
211 case EVENT_TYPE_STOP:
212 if (component == EVENT_CHANNEL_VP0) {
213 if (mali_activity[1].enabled) {
214 mali_activity_stop(0, mali_activity[1].key);
215 }
216 } else if (component >= EVENT_CHANNEL_FP0 && component <= EVENT_CHANNEL_FP7) {
217 if (mali_activity[0].enabled) {
218 mali_activity_stop(component - EVENT_CHANNEL_FP0, mali_activity[0].key);
219 }
220 }
221 break;
222
223 case EVENT_TYPE_SINGLE:
224 if (component == EVENT_CHANNEL_GPU) {
225 unsigned int reason = (event_id & 0xffff);
226
227 if (reason == EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE) {
228 gator_events_mali_log_dvfs_event(d0, d1);
229 }
230 }
231 break;
232
233 default:
234 break;
235 }
236}
237#endif
238
239#if defined(MALI_SUPPORT) && (MALI_SUPPORT == MALI_T6xx)
240
241mali_counter mali_activity[3];
242
243#if defined(MALI_JOB_SLOTS_EVENT_CHANGED)
244GATOR_DEFINE_PROBE(mali_job_slots_event, TP_PROTO(unsigned int event_id, unsigned int tgid, unsigned int pid, unsigned char job_id))
245#else
246GATOR_DEFINE_PROBE(mali_job_slots_event, TP_PROTO(unsigned int event_id, unsigned int tgid, unsigned int pid))
247#endif
248{
249 unsigned int component, state, unit;
250#if !defined(MALI_JOB_SLOTS_EVENT_CHANGED)
251 unsigned char job_id = 0;
252#endif
253
254 component = (event_id >> 16) & 0xFF; // component is an 8-bit field
255 state = (event_id >> 24) & 0xF; // state is a 4-bit field
256
257 switch (component) {
258 case 0:
259 unit = GPU_UNIT_FP;
260 break;
261 case 1:
262 unit = GPU_UNIT_VP;
263 break;
264 case 2:
265 unit = GPU_UNIT_CL;
266 break;
267 default:
268 unit = GPU_UNIT_NONE;
269 }
270
271 if (unit != GPU_UNIT_NONE) {
272 switch (state) {
273 case EVENT_TYPE_START:
274 if (mali_activity[component].enabled) {
275 mali_activity_enqueue(0, mali_activity[component].key, 1, (pid != 0 ? pid : tgid));
276 }
277 break;
278 case EVENT_TYPE_STOP:
279 default: // Some jobs can be soft-stopped, so ensure that this terminates the activity trace.
280 if (mali_activity[component].enabled) {
281 mali_activity_stop(0, mali_activity[component].key);
282 }
283 break;
284 }
285 }
286}
287#endif
288
289static int gator_trace_gpu_start(void)
290{
291 /*
292 * Returns nonzero for installation failed
293 * Absence of gpu trace points is not an error
294 */
295
296#if defined(MALI_SUPPORT)
297 memset(&mali_activities, 0, sizeof(mali_activities));
298#endif
299 mali_timeline_trace_registered = mali_job_slots_trace_registered = 0;
300
301#if defined(MALI_SUPPORT) && (MALI_SUPPORT != MALI_T6xx)
302 mali_activity_clear(mali_activity, ARRAY_SIZE(mali_activity));
303 if (!GATOR_REGISTER_TRACE(mali_timeline_event)) {
304 mali_timeline_trace_registered = 1;
305 }
306#endif
307
308#if defined(MALI_SUPPORT) && (MALI_SUPPORT == MALI_T6xx)
309 mali_activity_clear(mali_activity, ARRAY_SIZE(mali_activity));
310 if (!GATOR_REGISTER_TRACE(mali_job_slots_event)) {
311 mali_job_slots_trace_registered = 1;
312 }
313#endif
314
315 return 0;
316}
317
318static void gator_trace_gpu_stop(void)
319{
320#if defined(MALI_SUPPORT) && (MALI_SUPPORT != MALI_T6xx)
321 if (mali_timeline_trace_registered) {
322 GATOR_UNREGISTER_TRACE(mali_timeline_event);
323 }
324#endif
325
326#if defined(MALI_SUPPORT) && (MALI_SUPPORT == MALI_T6xx)
327 if (mali_job_slots_trace_registered) {
328 GATOR_UNREGISTER_TRACE(mali_job_slots_event);
329 }
330#endif
331
332 mali_timeline_trace_registered = mali_job_slots_trace_registered = 0;
333}
diff --git a/drivers/gator/gator_trace_power.c b/drivers/gator/gator_trace_power.c
new file mode 100644
index 00000000000..f2754b1c2b5
--- /dev/null
+++ b/drivers/gator/gator_trace_power.c
@@ -0,0 +1,203 @@
1/**
2 * Copyright (C) ARM Limited 2011-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10#include <linux/cpufreq.h>
11#include <trace/events/power.h>
12
13#if defined(__arm__)
14
15#include <asm/mach-types.h>
16
17#define implements_wfi() (!machine_is_omap3_beagle())
18
19#else
20
21#define implements_wfi() false
22
23#endif
24
25// cpu_frequency and cpu_idle trace points were introduced in Linux kernel v2.6.38
26// the now deprecated power_frequency trace point was available prior to 2.6.38, but only for x86
27#if GATOR_CPU_FREQ_SUPPORT
28enum {
29 POWER_CPU_FREQ,
30 POWER_CPU_IDLE,
31 POWER_TOTAL
32};
33
34static DEFINE_PER_CPU(ulong, idle_prev_state);
35static ulong power_cpu_enabled[POWER_TOTAL];
36static ulong power_cpu_key[POWER_TOTAL];
37
38static int gator_trace_power_create_files(struct super_block *sb, struct dentry *root)
39{
40 struct dentry *dir;
41 int cpu;
42 bool found_nonzero_freq = false;
43
44 // Even if CONFIG_CPU_FREQ is defined, it still may not be used. Check
45 // for non-zero values from cpufreq_quick_get
46 for_each_online_cpu(cpu) {
47 if (cpufreq_quick_get(cpu) > 0) {
48 found_nonzero_freq = true;
49 break;
50 }
51 }
52
53 if (found_nonzero_freq) {
54 // cpu_frequency
55 dir = gatorfs_mkdir(sb, root, "Linux_power_cpu_freq");
56 if (!dir) {
57 return -1;
58 }
59 gatorfs_create_ulong(sb, dir, "enabled", &power_cpu_enabled[POWER_CPU_FREQ]);
60 gatorfs_create_ro_ulong(sb, dir, "key", &power_cpu_key[POWER_CPU_FREQ]);
61 }
62
63 // cpu_idle
64 dir = gatorfs_mkdir(sb, root, "Linux_power_cpu_idle");
65 if (!dir) {
66 return -1;
67 }
68 gatorfs_create_ulong(sb, dir, "enabled", &power_cpu_enabled[POWER_CPU_IDLE]);
69 gatorfs_create_ro_ulong(sb, dir, "key", &power_cpu_key[POWER_CPU_IDLE]);
70
71 return 0;
72}
73
74// 'cpu' may not equal smp_processor_id(), i.e. may not be running on the core that is having the freq/idle state change
75GATOR_DEFINE_PROBE(cpu_frequency, TP_PROTO(unsigned int frequency, unsigned int cpu))
76{
77 cpu = lcpu_to_pcpu(cpu);
78 marshal_event_single64(cpu, power_cpu_key[POWER_CPU_FREQ], frequency * 1000L);
79}
80
81GATOR_DEFINE_PROBE(cpu_idle, TP_PROTO(unsigned int state, unsigned int cpu))
82{
83 cpu = lcpu_to_pcpu(cpu);
84
85 if (state == per_cpu(idle_prev_state, cpu)) {
86 return;
87 }
88
89 if (implements_wfi()) {
90 if (state == PWR_EVENT_EXIT) {
91 // transition from wfi to non-wfi
92 marshal_idle(cpu, MESSAGE_IDLE_EXIT);
93 } else {
94 // transition from non-wfi to wfi
95 marshal_idle(cpu, MESSAGE_IDLE_ENTER);
96 }
97 }
98
99 per_cpu(idle_prev_state, cpu) = state;
100
101 if (power_cpu_enabled[POWER_CPU_IDLE]) {
102 // Increment state so that no negative numbers are sent
103 marshal_event_single(cpu, power_cpu_key[POWER_CPU_IDLE], state + 1);
104 }
105}
106
107static void gator_trace_power_online(void)
108{
109 int pcpu = get_physical_cpu();
110 int lcpu = get_logical_cpu();
111 if (power_cpu_enabled[POWER_CPU_FREQ]) {
112 marshal_event_single64(pcpu, power_cpu_key[POWER_CPU_FREQ], cpufreq_quick_get(lcpu) * 1000L);
113 }
114}
115
116static void gator_trace_power_offline(void)
117{
118 // Set frequency to zero on an offline
119 int cpu = get_physical_cpu();
120 if (power_cpu_enabled[POWER_CPU_FREQ]) {
121 marshal_event_single(cpu, power_cpu_key[POWER_CPU_FREQ], 0);
122 }
123}
124
125static int gator_trace_power_start(void)
126{
127 int cpu;
128
129 // register tracepoints
130 if (power_cpu_enabled[POWER_CPU_FREQ])
131 if (GATOR_REGISTER_TRACE(cpu_frequency))
132 goto fail_cpu_frequency_exit;
133
134 // Always register for cpu:idle for detecting WFI, independent of power_cpu_enabled[POWER_CPU_IDLE]
135 if (GATOR_REGISTER_TRACE(cpu_idle))
136 goto fail_cpu_idle_exit;
137 pr_debug("gator: registered power event tracepoints\n");
138
139 for_each_present_cpu(cpu) {
140 per_cpu(idle_prev_state, cpu) = 0;
141 }
142
143 return 0;
144
145 // unregister tracepoints on error
146fail_cpu_idle_exit:
147 if (power_cpu_enabled[POWER_CPU_FREQ])
148 GATOR_UNREGISTER_TRACE(cpu_frequency);
149fail_cpu_frequency_exit:
150 pr_err("gator: power event tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n");
151
152 return -1;
153}
154
155static void gator_trace_power_stop(void)
156{
157 int i;
158
159 if (power_cpu_enabled[POWER_CPU_FREQ])
160 GATOR_UNREGISTER_TRACE(cpu_frequency);
161 GATOR_UNREGISTER_TRACE(cpu_idle);
162 pr_debug("gator: unregistered power event tracepoints\n");
163
164 for (i = 0; i < POWER_TOTAL; i++) {
165 power_cpu_enabled[i] = 0;
166 }
167}
168
169static void gator_trace_power_init(void)
170{
171 int i;
172 for (i = 0; i < POWER_TOTAL; i++) {
173 power_cpu_enabled[i] = 0;
174 power_cpu_key[i] = gator_events_get_key();
175 }
176}
177#else
178static int gator_trace_power_create_files(struct super_block *sb, struct dentry *root)
179{
180 return 0;
181}
182
183static void gator_trace_power_online(void)
184{
185}
186
187static void gator_trace_power_offline(void)
188{
189}
190
191static int gator_trace_power_start(void)
192{
193 return 0;
194}
195
196static void gator_trace_power_stop(void)
197{
198}
199
200static void gator_trace_power_init(void)
201{
202}
203#endif
diff --git a/drivers/gator/gator_trace_sched.c b/drivers/gator/gator_trace_sched.c
new file mode 100644
index 00000000000..65500862893
--- /dev/null
+++ b/drivers/gator/gator_trace_sched.c
@@ -0,0 +1,297 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10#include <trace/events/sched.h>
11#include "gator.h"
12
13#define TASK_MAP_ENTRIES 1024 /* must be power of 2 */
14#define TASK_MAX_COLLISIONS 2
15
16enum {
17 STATE_WAIT_ON_OTHER = 0,
18 STATE_CONTENTION,
19 STATE_WAIT_ON_IO,
20 CPU_WAIT_TOTAL
21};
22
23static DEFINE_PER_CPU(uint64_t *, taskname_keys);
24static DEFINE_PER_CPU(int, collecting);
25
26// this array is never read as the cpu wait charts are derived counters
27// the files are needed, nonetheless, to show that these counters are available
28static ulong cpu_wait_enabled[CPU_WAIT_TOTAL];
29static ulong sched_cpu_key[CPU_WAIT_TOTAL];
30
31static int sched_trace_create_files(struct super_block *sb, struct dentry *root)
32{
33 struct dentry *dir;
34
35 // CPU Wait - Contention
36 dir = gatorfs_mkdir(sb, root, "Linux_cpu_wait_contention");
37 if (!dir) {
38 return -1;
39 }
40 gatorfs_create_ulong(sb, dir, "enabled", &cpu_wait_enabled[STATE_CONTENTION]);
41 gatorfs_create_ro_ulong(sb, dir, "key", &sched_cpu_key[STATE_CONTENTION]);
42
43 // CPU Wait - I/O
44 dir = gatorfs_mkdir(sb, root, "Linux_cpu_wait_io");
45 if (!dir) {
46 return -1;
47 }
48 gatorfs_create_ulong(sb, dir, "enabled", &cpu_wait_enabled[STATE_WAIT_ON_IO]);
49 gatorfs_create_ro_ulong(sb, dir, "key", &sched_cpu_key[STATE_WAIT_ON_IO]);
50
51 return 0;
52}
53
54static void emit_pid_name(struct task_struct *task)
55{
56 bool found = false;
57 char taskcomm[TASK_COMM_LEN + 3];
58 unsigned long x, cpu = get_physical_cpu();
59 uint64_t *keys = &(per_cpu(taskname_keys, cpu)[(task->pid & 0xFF) * TASK_MAX_COLLISIONS]);
60 uint64_t value;
61
62 value = gator_chksum_crc32(task->comm);
63 value = (value << 32) | (uint32_t)task->pid;
64
65 // determine if the thread name was emitted already
66 for (x = 0; x < TASK_MAX_COLLISIONS; x++) {
67 if (keys[x] == value) {
68 found = true;
69 break;
70 }
71 }
72
73 if (!found) {
74 // shift values, new value always in front
75 uint64_t oldv, newv = value;
76 for (x = 0; x < TASK_MAX_COLLISIONS; x++) {
77 oldv = keys[x];
78 keys[x] = newv;
79 newv = oldv;
80 }
81
82 // emit pid names, cannot use get_task_comm, as it's not exported on all kernel versions
83 if (strlcpy(taskcomm, task->comm, TASK_COMM_LEN) == TASK_COMM_LEN - 1) {
84 // append ellipses if task->comm has length of TASK_COMM_LEN - 1
85 strcat(taskcomm, "...");
86 }
87
88 marshal_thread_name(task->pid, taskcomm);
89 }
90}
91
92static void collect_counters(u64 time, struct task_struct *task)
93{
94 int *buffer, len, cpu = get_physical_cpu();
95 long long *buffer64;
96 struct gator_interface *gi;
97
98 if (marshal_event_header(time)) {
99 list_for_each_entry(gi, &gator_events, list) {
100 if (gi->read) {
101 len = gi->read(&buffer);
102 marshal_event(len, buffer);
103 } else if (gi->read64) {
104 len = gi->read64(&buffer64);
105 marshal_event64(len, buffer64);
106 }
107 if (gi->read_proc && task != NULL) {
108 len = gi->read_proc(&buffer64, task);
109 marshal_event64(len, buffer64);
110 }
111 }
112 // Only check after writing all counters so that time and corresponding counters appear in the same frame
113 buffer_check(cpu, BLOCK_COUNTER_BUF, time);
114
115 // Commit buffers on timeout
116 if (gator_live_rate > 0 && time >= per_cpu(gator_buffer_commit_time, cpu)) {
117 static const int buftypes[] = { NAME_BUF, COUNTER_BUF, BLOCK_COUNTER_BUF, SCHED_TRACE_BUF, ACTIVITY_BUF };
118 int i;
119
120 for (i = 0; i < ARRAY_SIZE(buftypes); ++i) {
121 gator_commit_buffer(cpu, buftypes[i], time);
122 }
123
124 // spinlocks are noops on uniprocessor machines and mutexes do not work in sched_switch context in
125 // RT-Preempt full, so disable proactive flushing of the annotate frame on uniprocessor machines.
126#ifdef CONFIG_SMP
127 // Try to preemptively flush the annotate buffer to reduce the chance of the buffer being full
128 if (on_primary_core() && spin_trylock(&annotate_lock)) {
129 gator_commit_buffer(0, ANNOTATE_BUF, time);
130 spin_unlock(&annotate_lock);
131 }
132#endif
133 }
134 }
135}
136
137// special case used during a suspend of the system
138static void trace_sched_insert_idle(void)
139{
140 marshal_sched_trace_switch(0, 0);
141}
142
143static void gator_trace_emit_link(struct task_struct *p)
144{
145 int cookie;
146 int cpu = get_physical_cpu();
147
148 cookie = get_exec_cookie(cpu, p);
149 emit_pid_name(p);
150
151 marshal_link(cookie, p->tgid, p->pid);
152}
153
154GATOR_DEFINE_PROBE(sched_process_fork, TP_PROTO(struct task_struct *parent, struct task_struct *child))
155{
156 gator_trace_emit_link(child);
157}
158
159#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
160GATOR_DEFINE_PROBE(sched_process_exec, TP_PROTO(struct task_struct *p, pid_t old_pid, struct linux_binprm *bprm))
161{
162 gator_trace_emit_link(p);
163}
164#endif
165
166#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
167GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct rq *rq, struct task_struct *prev, struct task_struct *next))
168#else
169GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct task_struct *prev, struct task_struct *next))
170#endif
171{
172 int state;
173 int cpu = get_physical_cpu();
174
175 per_cpu(in_scheduler_context, cpu) = true;
176
177 // do as much work as possible before disabling interrupts
178 if (prev->state == TASK_RUNNING) {
179 state = STATE_CONTENTION;
180 } else if (prev->in_iowait) {
181 state = STATE_WAIT_ON_IO;
182 } else {
183 state = STATE_WAIT_ON_OTHER;
184 }
185
186 per_cpu(collecting, cpu) = 1;
187 collect_counters(gator_get_time(), prev);
188 per_cpu(collecting, cpu) = 0;
189
190#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)
191 gator_trace_emit_link(next);
192#endif
193 marshal_sched_trace_switch(next->pid, state);
194
195 per_cpu(in_scheduler_context, cpu) = false;
196}
197
198GATOR_DEFINE_PROBE(sched_process_free, TP_PROTO(struct task_struct *p))
199{
200 marshal_sched_trace_exit(p->tgid, p->pid);
201}
202
203static void do_nothing(void *info)
204{
205 // Intentionally do nothing
206 (void)info;
207}
208
209static int register_scheduler_tracepoints(void)
210{
211 // register tracepoints
212 if (GATOR_REGISTER_TRACE(sched_process_fork))
213 goto fail_sched_process_fork;
214#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
215 if (GATOR_REGISTER_TRACE(sched_process_exec))
216 goto fail_sched_process_exec;
217#endif
218 if (GATOR_REGISTER_TRACE(sched_switch))
219 goto fail_sched_switch;
220 if (GATOR_REGISTER_TRACE(sched_process_free))
221 goto fail_sched_process_free;
222 pr_debug("gator: registered tracepoints\n");
223
224 // Now that the scheduler tracepoint is registered, force a context switch
225 // on all cpus to capture what is currently running.
226 on_each_cpu(do_nothing, NULL, 0);
227
228 return 0;
229
230 // unregister tracepoints on error
231fail_sched_process_free:
232 GATOR_UNREGISTER_TRACE(sched_switch);
233fail_sched_switch:
234 GATOR_UNREGISTER_TRACE(sched_process_fork);
235#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
236fail_sched_process_exec:
237 GATOR_UNREGISTER_TRACE(sched_process_exec);
238#endif
239fail_sched_process_fork:
240 pr_err("gator: tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n");
241
242 return -1;
243}
244
245static void unregister_scheduler_tracepoints(void)
246{
247 GATOR_UNREGISTER_TRACE(sched_process_fork);
248#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
249 GATOR_UNREGISTER_TRACE(sched_process_exec);
250#endif
251 GATOR_UNREGISTER_TRACE(sched_switch);
252 GATOR_UNREGISTER_TRACE(sched_process_free);
253 pr_debug("gator: unregistered tracepoints\n");
254}
255
256static void gator_trace_sched_stop(void)
257{
258 int cpu;
259
260 unregister_scheduler_tracepoints();
261
262 for_each_present_cpu(cpu) {
263 kfree(per_cpu(taskname_keys, cpu));
264 }
265}
266
267static int gator_trace_sched_start(void)
268{
269 int cpu, size;
270 int ret;
271
272 for_each_present_cpu(cpu) {
273 size = TASK_MAP_ENTRIES * TASK_MAX_COLLISIONS * sizeof(uint64_t);
274 per_cpu(taskname_keys, cpu) = (uint64_t *)kmalloc(size, GFP_KERNEL);
275 if (!per_cpu(taskname_keys, cpu))
276 return -1;
277 memset(per_cpu(taskname_keys, cpu), 0, size);
278 }
279
280 ret = register_scheduler_tracepoints();
281
282 return ret;
283}
284
285static void gator_trace_sched_offline(void)
286{
287 trace_sched_insert_idle();
288}
289
290static void gator_trace_sched_init(void)
291{
292 int i;
293 for (i = 0; i < CPU_WAIT_TOTAL; i++) {
294 cpu_wait_enabled[i] = 0;
295 sched_cpu_key[i] = gator_events_get_key();
296 }
297}
diff --git a/drivers/gator/mali/mali_dd_gator_api.h b/drivers/gator/mali/mali_dd_gator_api.h
new file mode 100644
index 00000000000..104b34f2d72
--- /dev/null
+++ b/drivers/gator/mali/mali_dd_gator_api.h
@@ -0,0 +1,40 @@
1#if !defined(MALI_DDK_GATOR_API_VERSION)
2 #define MALI_DDK_GATOR_API_VERSION 3
3#endif
4#if !defined(MALI_TRUE)
5 #define MALI_TRUE ((unsigned int)1)
6#endif
7
8#if !defined(MALI_FALSE)
9 #define MALI_FALSE ((unsigned int)0)
10#endif
11
12struct mali_dd_hwcnt_info {
13
14 /* Passed from Gator to kbase */
15 //u32 in_mali_dd_hwcnt_version;
16 unsigned short int bitmask[4];
17
18 /* Passed from kbase to Gator */
19
20 /* ptr to counter dump memory */
21 void *kernel_dump_buffer;
22
23 /* size of counter dump memory */
24 unsigned int size;
25
26 unsigned int gpu_id;
27
28 unsigned int nr_cores;
29
30 unsigned int nr_core_groups;
31
32 /* The cached present bitmaps - these are the same as the corresponding hardware registers*/
33 unsigned long int shader_present_bitmap;
34};
35
36struct mali_dd_hwcnt_handles;
37extern struct mali_dd_hwcnt_handles* mali_dd_hwcnt_init(struct mali_dd_hwcnt_info *in_out_info);
38extern void mali_dd_hwcnt_clear(struct mali_dd_hwcnt_info *in_out_info, struct mali_dd_hwcnt_handles *opaque_handles);
39extern unsigned int kbase_dd_instr_hwcnt_dump_complete(struct mali_dd_hwcnt_handles *opaque_handles, unsigned int * const success);
40extern unsigned int kbase_dd_instr_hwcnt_dump_irq(struct mali_dd_hwcnt_handles *opaque_handles);
diff --git a/drivers/gator/mali/mali_mjollnir_profiling_gator_api.h b/drivers/gator/mali/mali_mjollnir_profiling_gator_api.h
new file mode 100644
index 00000000000..ff00d90cee7
--- /dev/null
+++ b/drivers/gator/mali/mali_mjollnir_profiling_gator_api.h
@@ -0,0 +1,163 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10#ifndef __MALI_MJOLLNIR_PROFILING_GATOR_API_H__
11#define __MALI_MJOLLNIR_PROFILING_GATOR_API_H__
12
13#ifdef __cplusplus
14extern "C"
15{
16#endif
17
18
19/*
20 * The number of processor cores. Update to suit your hardware implementation.
21 */
22#define MAX_NUM_FP_CORES (4)
23#define MAX_NUM_VP_CORES (1)
24#define MAX_NUM_L2_CACHE_CORES (1)
25
26enum counters
27{
28 /* Timeline activity */
29 ACTIVITY_VP_0 = 0,
30 ACTIVITY_FP_0,
31 ACTIVITY_FP_1,
32 ACTIVITY_FP_2,
33 ACTIVITY_FP_3,
34
35 /* L2 cache counters */
36 COUNTER_L2_0_C0,
37 COUNTER_L2_0_C1,
38
39 /* Vertex processor counters */
40 COUNTER_VP_0_C0,
41 COUNTER_VP_0_C1,
42
43 /* Fragment processor counters */
44 COUNTER_FP_0_C0,
45 COUNTER_FP_0_C1,
46 COUNTER_FP_1_C0,
47 COUNTER_FP_1_C1,
48 COUNTER_FP_2_C0,
49 COUNTER_FP_2_C1,
50 COUNTER_FP_3_C0,
51 COUNTER_FP_3_C1,
52
53 /* EGL Software Counters */
54 COUNTER_EGL_BLIT_TIME,
55
56 /* GLES Software Counters */
57 COUNTER_GLES_DRAW_ELEMENTS_CALLS,
58 COUNTER_GLES_DRAW_ELEMENTS_NUM_INDICES,
59 COUNTER_GLES_DRAW_ELEMENTS_NUM_TRANSFORMED,
60 COUNTER_GLES_DRAW_ARRAYS_CALLS,
61 COUNTER_GLES_DRAW_ARRAYS_NUM_TRANSFORMED,
62 COUNTER_GLES_DRAW_POINTS,
63 COUNTER_GLES_DRAW_LINES,
64 COUNTER_GLES_DRAW_LINE_LOOP,
65 COUNTER_GLES_DRAW_LINE_STRIP,
66 COUNTER_GLES_DRAW_TRIANGLES,
67 COUNTER_GLES_DRAW_TRIANGLE_STRIP,
68 COUNTER_GLES_DRAW_TRIANGLE_FAN,
69 COUNTER_GLES_NON_VBO_DATA_COPY_TIME,
70 COUNTER_GLES_UNIFORM_BYTES_COPIED_TO_MALI,
71 COUNTER_GLES_UPLOAD_TEXTURE_TIME,
72 COUNTER_GLES_UPLOAD_VBO_TIME,
73 COUNTER_GLES_NUM_FLUSHES,
74 COUNTER_GLES_NUM_VSHADERS_GENERATED,
75 COUNTER_GLES_NUM_FSHADERS_GENERATED,
76 COUNTER_GLES_VSHADER_GEN_TIME,
77 COUNTER_GLES_FSHADER_GEN_TIME,
78 COUNTER_GLES_INPUT_TRIANGLES,
79 COUNTER_GLES_VXCACHE_HIT,
80 COUNTER_GLES_VXCACHE_MISS,
81 COUNTER_GLES_VXCACHE_COLLISION,
82 COUNTER_GLES_CULLED_TRIANGLES,
83 COUNTER_GLES_CULLED_LINES,
84 COUNTER_GLES_BACKFACE_TRIANGLES,
85 COUNTER_GLES_GBCLIP_TRIANGLES,
86 COUNTER_GLES_GBCLIP_LINES,
87 COUNTER_GLES_TRIANGLES_DRAWN,
88 COUNTER_GLES_DRAWCALL_TIME,
89 COUNTER_GLES_TRIANGLES_COUNT,
90 COUNTER_GLES_INDEPENDENT_TRIANGLES_COUNT,
91 COUNTER_GLES_STRIP_TRIANGLES_COUNT,
92 COUNTER_GLES_FAN_TRIANGLES_COUNT,
93 COUNTER_GLES_LINES_COUNT,
94 COUNTER_GLES_INDEPENDENT_LINES_COUNT,
95 COUNTER_GLES_STRIP_LINES_COUNT,
96 COUNTER_GLES_LOOP_LINES_COUNT,
97
98 COUNTER_FILMSTRIP,
99 COUNTER_FREQUENCY,
100 COUNTER_VOLTAGE,
101
102 NUMBER_OF_EVENTS
103};
104
105#define FIRST_ACTIVITY_EVENT ACTIVITY_VP_0
106#define LAST_ACTIVITY_EVENT ACTIVITY_FP_3
107
108#define FIRST_HW_COUNTER COUNTER_L2_0_C0
109#define LAST_HW_COUNTER COUNTER_FP_3_C1
110
111#define FIRST_SW_COUNTER COUNTER_EGL_BLIT_TIME
112#define LAST_SW_COUNTER COUNTER_GLES_LOOP_LINES_COUNT
113
114/* Signifies that the system is able to report voltage and frequency numbers. */
115#define DVFS_REPORTED_BY_DDK 1
116
117/**
118 * Structure to pass performance counter data of a Mali core
119 */
120typedef struct _mali_profiling_core_counters
121{
122 u32 source0;
123 u32 value0;
124 u32 source1;
125 u32 value1;
126} _mali_profiling_core_counters;
127
128/*
129 * For compatibility with utgard.
130 */
131typedef struct _mali_profiling_l2_counter_values
132{
133 struct _mali_profiling_core_counters cores[MAX_NUM_L2_CACHE_CORES];
134} _mali_profiling_l2_counter_values;
135
136typedef struct _mali_profiling_mali_version
137{
138 u32 mali_product_id;
139 u32 mali_version_major;
140 u32 mali_version_minor;
141 u32 num_of_l2_cores;
142 u32 num_of_fp_cores;
143 u32 num_of_vp_cores;
144} _mali_profiling_mali_version;
145
146extern void _mali_profiling_get_mali_version(struct _mali_profiling_mali_version *values);
147extern u32 _mali_profiling_get_l2_counters(_mali_profiling_l2_counter_values *values);
148
149/*
150 * List of possible actions allowing DDK to be controlled by Streamline.
151 * The following numbers are used by DDK to control the frame buffer dumping.
152 */
153#define FBDUMP_CONTROL_ENABLE (1)
154#define FBDUMP_CONTROL_RATE (2)
155#define SW_COUNTER_ENABLE (3)
156#define FBDUMP_CONTROL_RESIZE_FACTOR (4)
157
158
159#ifdef __cplusplus
160}
161#endif
162
163#endif /* __MALI_MJOLLNIR_PROFILING_GATOR_API_H__ */
diff --git a/drivers/gator/mali/mali_utgard_profiling_gator_api.h b/drivers/gator/mali/mali_utgard_profiling_gator_api.h
new file mode 100644
index 00000000000..43c57604288
--- /dev/null
+++ b/drivers/gator/mali/mali_utgard_profiling_gator_api.h
@@ -0,0 +1,201 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10#ifndef __MALI_UTGARD_PROFILING_GATOR_API_H__
11#define __MALI_UTGARD_PROFILING_GATOR_API_H__
12
13#ifdef __cplusplus
14extern "C"
15{
16#endif
17
18#define MALI_PROFILING_API_VERSION 4
19
20#define MAX_NUM_L2_CACHE_CORES 3
21#define MAX_NUM_FP_CORES 8
22#define MAX_NUM_VP_CORES 1
23
24/** The list of events supported by the Mali DDK. */
25typedef enum
26{
27 /* Vertex processor activity */
28 ACTIVITY_VP_0 = 0,
29
30 /* Fragment processor activity */
31 ACTIVITY_FP_0, /* 1 */
32 ACTIVITY_FP_1,
33 ACTIVITY_FP_2,
34 ACTIVITY_FP_3,
35 ACTIVITY_FP_4,
36 ACTIVITY_FP_5,
37 ACTIVITY_FP_6,
38 ACTIVITY_FP_7,
39
40 /* L2 cache counters */
41 COUNTER_L2_0_C0,
42 COUNTER_L2_0_C1,
43 COUNTER_L2_1_C0,
44 COUNTER_L2_1_C1,
45 COUNTER_L2_2_C0,
46 COUNTER_L2_2_C1,
47
48 /* Vertex processor counters */
49 COUNTER_VP_0_C0, /*15*/
50 COUNTER_VP_0_C1,
51
52 /* Fragment processor counters */
53 COUNTER_FP_0_C0,
54 COUNTER_FP_0_C1,
55 COUNTER_FP_1_C0,
56 COUNTER_FP_1_C1,
57 COUNTER_FP_2_C0,
58 COUNTER_FP_2_C1,
59 COUNTER_FP_3_C0,
60 COUNTER_FP_3_C1,
61 COUNTER_FP_4_C0,
62 COUNTER_FP_4_C1,
63 COUNTER_FP_5_C0,
64 COUNTER_FP_5_C1,
65 COUNTER_FP_6_C0,
66 COUNTER_FP_6_C1,
67 COUNTER_FP_7_C0,
68 COUNTER_FP_7_C1, /* 32 */
69
70 /*
71 * If more hardware counters are added, the _mali_osk_hw_counter_table
72 * below should also be updated.
73 */
74
75 /* EGL software counters */
76 COUNTER_EGL_BLIT_TIME,
77
78 /* GLES software counters */
79 COUNTER_GLES_DRAW_ELEMENTS_CALLS,
80 COUNTER_GLES_DRAW_ELEMENTS_NUM_INDICES,
81 COUNTER_GLES_DRAW_ELEMENTS_NUM_TRANSFORMED,
82 COUNTER_GLES_DRAW_ARRAYS_CALLS,
83 COUNTER_GLES_DRAW_ARRAYS_NUM_TRANSFORMED,
84 COUNTER_GLES_DRAW_POINTS,
85 COUNTER_GLES_DRAW_LINES,
86 COUNTER_GLES_DRAW_LINE_LOOP,
87 COUNTER_GLES_DRAW_LINE_STRIP,
88 COUNTER_GLES_DRAW_TRIANGLES,
89 COUNTER_GLES_DRAW_TRIANGLE_STRIP,
90 COUNTER_GLES_DRAW_TRIANGLE_FAN,
91 COUNTER_GLES_NON_VBO_DATA_COPY_TIME,
92 COUNTER_GLES_UNIFORM_BYTES_COPIED_TO_MALI,
93 COUNTER_GLES_UPLOAD_TEXTURE_TIME,
94 COUNTER_GLES_UPLOAD_VBO_TIME,
95 COUNTER_GLES_NUM_FLUSHES,
96 COUNTER_GLES_NUM_VSHADERS_GENERATED,
97 COUNTER_GLES_NUM_FSHADERS_GENERATED,
98 COUNTER_GLES_VSHADER_GEN_TIME,
99 COUNTER_GLES_FSHADER_GEN_TIME,
100 COUNTER_GLES_INPUT_TRIANGLES,
101 COUNTER_GLES_VXCACHE_HIT,
102 COUNTER_GLES_VXCACHE_MISS,
103 COUNTER_GLES_VXCACHE_COLLISION,
104 COUNTER_GLES_CULLED_TRIANGLES,
105 COUNTER_GLES_CULLED_LINES,
106 COUNTER_GLES_BACKFACE_TRIANGLES,
107 COUNTER_GLES_GBCLIP_TRIANGLES,
108 COUNTER_GLES_GBCLIP_LINES,
109 COUNTER_GLES_TRIANGLES_DRAWN,
110 COUNTER_GLES_DRAWCALL_TIME,
111 COUNTER_GLES_TRIANGLES_COUNT,
112 COUNTER_GLES_INDEPENDENT_TRIANGLES_COUNT,
113 COUNTER_GLES_STRIP_TRIANGLES_COUNT,
114 COUNTER_GLES_FAN_TRIANGLES_COUNT,
115 COUNTER_GLES_LINES_COUNT,
116 COUNTER_GLES_INDEPENDENT_LINES_COUNT,
117 COUNTER_GLES_STRIP_LINES_COUNT,
118 COUNTER_GLES_LOOP_LINES_COUNT,
119
120 /* Framebuffer capture pseudo-counter */
121 COUNTER_FILMSTRIP,
122
123 NUMBER_OF_EVENTS
124} _mali_osk_counter_id;
125
126#define FIRST_ACTIVITY_EVENT ACTIVITY_VP_0
127#define LAST_ACTIVITY_EVENT ACTIVITY_FP_7
128
129#define FIRST_HW_COUNTER COUNTER_L2_0_C0
130#define LAST_HW_COUNTER COUNTER_FP_7_C1
131
132#define FIRST_SW_COUNTER COUNTER_EGL_BLIT_TIME
133#define LAST_SW_COUNTER COUNTER_GLES_LOOP_LINES_COUNT
134
135#define FIRST_SPECIAL_COUNTER COUNTER_FILMSTRIP
136#define LAST_SPECIAL_COUNTER COUNTER_FILMSTRIP
137
138/**
139 * Structure to pass performance counter data of a Mali core
140 */
141typedef struct _mali_profiling_core_counters
142{
143 u32 source0;
144 u32 value0;
145 u32 source1;
146 u32 value1;
147} _mali_profiling_core_counters;
148
149/**
150 * Structure to pass performance counter data of Mali L2 cache cores
151 */
152typedef struct _mali_profiling_l2_counter_values
153{
154 struct _mali_profiling_core_counters cores[MAX_NUM_L2_CACHE_CORES];
155} _mali_profiling_l2_counter_values;
156
157/**
158 * Structure to pass data defining Mali instance in use:
159 *
160 * mali_product_id - Mali product id
161 * mali_version_major - Mali version major number
162 * mali_version_minor - Mali version minor number
163 * num_of_l2_cores - number of L2 cache cores
164 * num_of_fp_cores - number of fragment processor cores
165 * num_of_vp_cores - number of vertex processor cores
166 */
167typedef struct _mali_profiling_mali_version
168{
169 u32 mali_product_id;
170 u32 mali_version_major;
171 u32 mali_version_minor;
172 u32 num_of_l2_cores;
173 u32 num_of_fp_cores;
174 u32 num_of_vp_cores;
175} _mali_profiling_mali_version;
176
177/*
178 * List of possible actions to be controlled by Streamline.
179 * The following numbers are used by gator to control the frame buffer dumping and s/w counter reporting.
180 * We cannot use the enums in mali_uk_types.h because they are unknown inside gator.
181 */
182#define FBDUMP_CONTROL_ENABLE (1)
183#define FBDUMP_CONTROL_RATE (2)
184#define SW_COUNTER_ENABLE (3)
185#define FBDUMP_CONTROL_RESIZE_FACTOR (4)
186
187void _mali_profiling_control(u32 action, u32 value);
188
189u32 _mali_profiling_get_l2_counters(_mali_profiling_l2_counter_values *values);
190
191int _mali_profiling_set_event(u32 counter_id, s32 event_id);
192
193u32 _mali_profiling_get_api_version(void);
194
195void _mali_profiling_get_mali_version(struct _mali_profiling_mali_version *values);
196
197#ifdef __cplusplus
198}
199#endif
200
201#endif /* __MALI_UTGARD_PROFILING_GATOR_API_H__ */
diff --git a/drivers/gator/mali_t6xx.mk b/drivers/gator/mali_t6xx.mk
new file mode 100644
index 00000000000..fa7571ded17
--- /dev/null
+++ b/drivers/gator/mali_t6xx.mk
@@ -0,0 +1,39 @@
1# Defines for Mali-T6xx driver
2EXTRA_CFLAGS += -DMALI_USE_UMP=1 \
3 -DMALI_LICENSE_IS_GPL=1 \
4 -DMALI_BASE_TRACK_MEMLEAK=0 \
5 -DMALI_DEBUG=0 \
6 -DMALI_ERROR_INJECT_ON=0 \
7 -DMALI_CUSTOMER_RELEASE=1 \
8 -DMALI_UNIT_TEST=0 \
9 -DMALI_BACKEND_KERNEL=1 \
10 -DMALI_NO_MALI=0
11
12DDK_DIR ?= .
13ifneq ($(wildcard $(DDK_DIR)/drivers/gpu/arm/t6xx),)
14KBASE_DIR = $(DDK_DIR)/drivers/gpu/arm/t6xx/kbase
15OSK_DIR = $(DDK_DIR)/drivers/gpu/arm/t6xx/kbase/osk
16endif
17
18ifneq ($(wildcard $(DDK_DIR)/drivers/gpu/arm/midgard),)
19KBASE_DIR = $(DDK_DIR)/drivers/gpu/arm/midgard
20OSK_DIR = $(DDK_DIR)/drivers/gpu/arm/midgard/osk
21EXTRA_CFLAGS += -DMALI_DIR_MIDGARD=1
22endif
23
24ifneq ($(wildcard $(DDK_DIR)/drivers/gpu/arm/midgard/mali_dd_gator_api.h),)
25EXTRA_CFLAGS += -DMALI_SIMPLE_API=1
26endif
27
28UMP_DIR = $(DDK_DIR)/include/linux
29
30# Include directories in the DDK
31EXTRA_CFLAGS += -I$(KBASE_DIR)/ \
32 -I$(KBASE_DIR)/.. \
33 -I$(OSK_DIR)/.. \
34 -I$(UMP_DIR)/.. \
35 -I$(DDK_DIR)/include \
36 -I$(KBASE_DIR)/osk/src/linux/include \
37 -I$(KBASE_DIR)/platform_dummy \
38 -I$(KBASE_DIR)/src
39
diff --git a/tools/gator/daemon/Android.mk b/tools/gator/daemon/Android.mk
new file mode 100644
index 00000000000..44c069cc7e2
--- /dev/null
+++ b/tools/gator/daemon/Android.mk
@@ -0,0 +1,65 @@
1LOCAL_PATH := $(call my-dir)
2include $(CLEAR_VARS)
3
4XML_H := $(shell cd $(LOCAL_PATH) && make events_xml.h defaults_xml.h)
5
6LOCAL_CFLAGS += -Wall -O3 -mthumb-interwork -fno-exceptions -pthread -DETCDIR=\"/etc\" -Ilibsensors
7
8LOCAL_SRC_FILES := \
9 Buffer.cpp \
10 CapturedXML.cpp \
11 Child.cpp \
12 ConfigurationXML.cpp \
13 Driver.cpp \
14 DriverSource.cpp \
15 DynBuf.cpp \
16 EventsXML.cpp \
17 ExternalSource.cpp \
18 FSDriver.cpp \
19 Fifo.cpp \
20 Hwmon.cpp \
21 KMod.cpp \
22 LocalCapture.cpp \
23 Logging.cpp \
24 main.cpp \
25 MaliVideoDriver.cpp \
26 Monitor.cpp \
27 OlySocket.cpp \
28 OlyUtility.cpp \
29 PerfBuffer.cpp \
30 PerfDriver.cpp \
31 PerfGroup.cpp \
32 PerfSource.cpp \
33 Proc.cpp \
34 Sender.cpp \
35 SessionData.cpp \
36 SessionXML.cpp \
37 Source.cpp \
38 StreamlineSetup.cpp \
39 UEvent.cpp \
40 UserSpaceSource.cpp \
41 libsensors/access.c \
42 libsensors/conf-lex.c \
43 libsensors/conf-parse.c \
44 libsensors/data.c \
45 libsensors/error.c \
46 libsensors/general.c \
47 libsensors/init.c \
48 libsensors/sysfs.c \
49 mxml/mxml-attr.c \
50 mxml/mxml-entity.c \
51 mxml/mxml-file.c \
52 mxml/mxml-get.c \
53 mxml/mxml-index.c \
54 mxml/mxml-node.c \
55 mxml/mxml-private.c \
56 mxml/mxml-search.c \
57 mxml/mxml-set.c \
58 mxml/mxml-string.c
59
60LOCAL_C_INCLUDES := $(LOCAL_PATH)
61
62LOCAL_MODULE := gatord
63LOCAL_MODULE_TAGS := optional
64
65include $(BUILD_EXECUTABLE)
diff --git a/tools/gator/daemon/Application.mk b/tools/gator/daemon/Application.mk
new file mode 100644
index 00000000000..631ba54148d
--- /dev/null
+++ b/tools/gator/daemon/Application.mk
@@ -0,0 +1 @@
APP_PLATFORM := android-8
diff --git a/tools/gator/daemon/Buffer.cpp b/tools/gator/daemon/Buffer.cpp
new file mode 100644
index 00000000000..dd19f7f8be7
--- /dev/null
+++ b/tools/gator/daemon/Buffer.cpp
@@ -0,0 +1,391 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "Buffer.h"
10
11#include "Logging.h"
12#include "Sender.h"
13#include "SessionData.h"
14
15#define mask (mSize - 1)
16
17enum {
18 CODE_PEA = 1,
19 CODE_KEYS = 2,
20 CODE_FORMAT = 3,
21 CODE_MAPS = 4,
22 CODE_COMM = 5,
23 CODE_KEYS_OLD = 6,
24};
25
26// Summary Frame Messages
27enum {
28 MESSAGE_SUMMARY = 1,
29 MESSAGE_CORE_NAME = 3,
30};
31
32// From gator_marshaling.c
33#define NEWLINE_CANARY \
34 /* Unix */ \
35 "1\n" \
36 /* Windows */ \
37 "2\r\n" \
38 /* Mac OS */ \
39 "3\r" \
40 /* RISC OS */ \
41 "4\n\r" \
42 /* Add another character so the length isn't 0x0a bytes */ \
43 "5"
44
45Buffer::Buffer(const int32_t core, const int32_t buftype, const int size, sem_t *const readerSem) : mCore(core), mBufType(buftype), mSize(size), mReadPos(0), mWritePos(0), mCommitPos(0), mAvailable(true), mIsDone(false), mBuf(new char[mSize]), mCommitTime(gSessionData->mLiveRate), mReaderSem(readerSem) {
46 if ((mSize & mask) != 0) {
47 logg->logError(__FILE__, __LINE__, "Buffer size is not a power of 2");
48 handleException();
49 }
50 frame();
51}
52
53Buffer::~Buffer() {
54 delete [] mBuf;
55}
56
57void Buffer::write(Sender *const sender) {
58 if (!commitReady()) {
59 return;
60 }
61
62 // determine the size of two halves
63 int length1 = mCommitPos - mReadPos;
64 char *buffer1 = mBuf + mReadPos;
65 int length2 = 0;
66 char *buffer2 = mBuf;
67 if (length1 < 0) {
68 length1 = mSize - mReadPos;
69 length2 = mCommitPos;
70 }
71
72 logg->logMessage("Sending data length1: %i length2: %i", length1, length2);
73
74 // start, middle or end
75 if (length1 > 0) {
76 sender->writeData(buffer1, length1, RESPONSE_APC_DATA);
77 }
78
79 // possible wrap around
80 if (length2 > 0) {
81 sender->writeData(buffer2, length2, RESPONSE_APC_DATA);
82 }
83
84 mReadPos = mCommitPos;
85}
86
87bool Buffer::commitReady() const {
88 return mCommitPos != mReadPos;
89}
90
91int Buffer::bytesAvailable() const {
92 int filled = mWritePos - mReadPos;
93 if (filled < 0) {
94 filled += mSize;
95 }
96
97 int remaining = mSize - filled;
98
99 if (mAvailable) {
100 // Give some extra room; also allows space to insert the overflow error packet
101 remaining -= 200;
102 } else {
103 // Hysteresis, prevents multiple overflow messages
104 remaining -= 2000;
105 }
106
107 return remaining;
108}
109
110bool Buffer::checkSpace(const int bytes) {
111 const int remaining = bytesAvailable();
112
113 if (remaining < bytes) {
114 mAvailable = false;
115 } else {
116 mAvailable = true;
117 }
118
119 return mAvailable;
120}
121
122int Buffer::contiguousSpaceAvailable() const {
123 int remaining = bytesAvailable();
124 int contiguous = mSize - mWritePos;
125 if (remaining < contiguous) {
126 return remaining;
127 } else {
128 return contiguous;
129 }
130}
131
132void Buffer::commit(const uint64_t time) {
133 // post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload
134 const int typeLength = gSessionData->mLocalCapture ? 0 : 1;
135 int length = mWritePos - mCommitPos;
136 if (length < 0) {
137 length += mSize;
138 }
139 length = length - typeLength - sizeof(int32_t);
140 for (size_t byte = 0; byte < sizeof(int32_t); byte++) {
141 mBuf[(mCommitPos + typeLength + byte) & mask] = (length >> byte * 8) & 0xFF;
142 }
143
144 logg->logMessage("Committing data mReadPos: %i mWritePos: %i mCommitPos: %i", mReadPos, mWritePos, mCommitPos);
145 mCommitPos = mWritePos;
146
147 if (gSessionData->mLiveRate > 0) {
148 while (time > mCommitTime) {
149 mCommitTime += gSessionData->mLiveRate;
150 }
151 }
152
153 if (!mIsDone) {
154 frame();
155 }
156
157 // send a notification that data is ready
158 sem_post(mReaderSem);
159}
160
161void Buffer::check(const uint64_t time) {
162 int filled = mWritePos - mCommitPos;
163 if (filled < 0) {
164 filled += mSize;
165 }
166 if (filled >= ((mSize * 3) / 4) || (gSessionData->mLiveRate > 0 && time >= mCommitTime)) {
167 commit(time);
168 }
169}
170
171void Buffer::packInt(char *const buf, const int size, int &writePos, int32_t x) {
172 int packedBytes = 0;
173 int more = true;
174 while (more) {
175 // low order 7 bits of x
176 char b = x & 0x7f;
177 x >>= 7;
178
179 if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) {
180 more = false;
181 } else {
182 b |= 0x80;
183 }
184
185 buf[(writePos + packedBytes) & /*mask*/(size - 1)] = b;
186 packedBytes++;
187 }
188
189 writePos = (writePos + packedBytes) & /*mask*/(size - 1);
190}
191
192void Buffer::packInt(int32_t x) {
193 packInt(mBuf, mSize, mWritePos, x);
194}
195
196void Buffer::packInt64(int64_t x) {
197 int packedBytes = 0;
198 int more = true;
199 while (more) {
200 // low order 7 bits of x
201 char b = x & 0x7f;
202 x >>= 7;
203
204 if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) {
205 more = false;
206 } else {
207 b |= 0x80;
208 }
209
210 mBuf[(mWritePos + packedBytes) & mask] = b;
211 packedBytes++;
212 }
213
214 mWritePos = (mWritePos + packedBytes) & mask;
215}
216
217void Buffer::writeBytes(const void *const data, size_t count) {
218 size_t i;
219 for (i = 0; i < count; ++i) {
220 mBuf[(mWritePos + i) & mask] = static_cast<const char *>(data)[i];
221 }
222
223 mWritePos = (mWritePos + i) & mask;
224}
225
226void Buffer::writeString(const char *const str) {
227 const int len = strlen(str);
228 packInt(len);
229 writeBytes(str, len);
230}
231
232void Buffer::frame() {
233 if (!gSessionData->mLocalCapture) {
234 packInt(RESPONSE_APC_DATA);
235 }
236 // Reserve space for the length
237 mWritePos += sizeof(int32_t);
238 packInt(mBufType);
239 packInt(mCore);
240}
241
242void Buffer::summary(const int64_t timestamp, const int64_t uptime, const int64_t monotonicDelta, const char *const uname) {
243 packInt(MESSAGE_SUMMARY);
244 writeString(NEWLINE_CANARY);
245 packInt64(timestamp);
246 packInt64(uptime);
247 packInt64(monotonicDelta);
248 writeString("uname");
249 writeString(uname);
250 writeString("");
251 check(1);
252}
253
254void Buffer::coreName(const int core, const int cpuid, const char *const name) {
255 if (checkSpace(3 * MAXSIZE_PACK32 + 0x100)) {
256 packInt(MESSAGE_CORE_NAME);
257 packInt(core);
258 packInt(cpuid);
259 writeString(name);
260 }
261 check(1);
262}
263
264bool Buffer::eventHeader(const uint64_t curr_time) {
265 bool retval = false;
266 if (checkSpace(MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
267 packInt(0); // key of zero indicates a timestamp
268 packInt64(curr_time);
269 retval = true;
270 }
271
272 return retval;
273}
274
275bool Buffer::eventTid(const int tid) {
276 bool retval = false;
277 if (checkSpace(2 * MAXSIZE_PACK32)) {
278 packInt(1); // key of 1 indicates a tid
279 packInt(tid);
280 retval = true;
281 }
282
283 return retval;
284}
285
286void Buffer::event(const int32_t key, const int32_t value) {
287 if (checkSpace(2 * MAXSIZE_PACK32)) {
288 packInt(key);
289 packInt(value);
290 }
291}
292
293void Buffer::event64(const int64_t key, const int64_t value) {
294 if (checkSpace(2 * MAXSIZE_PACK64)) {
295 packInt64(key);
296 packInt64(value);
297 }
298}
299
300void Buffer::pea(const struct perf_event_attr *const pea, int key) {
301 if (checkSpace(2 * MAXSIZE_PACK32 + pea->size)) {
302 packInt(CODE_PEA);
303 writeBytes(pea, pea->size);
304 packInt(key);
305 } else {
306 logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
307 handleException();
308 }
309 // Don't know the real perf time so use 1 as it will work for now
310 check(1);
311}
312
313void Buffer::keys(const int count, const __u64 *const ids, const int *const keys) {
314 if (checkSpace(2 * MAXSIZE_PACK32 + count * (MAXSIZE_PACK32 + MAXSIZE_PACK64))) {
315 packInt(CODE_KEYS);
316 packInt(count);
317 for (int i = 0; i < count; ++i) {
318 packInt64(ids[i]);
319 packInt(keys[i]);
320 }
321 } else {
322 logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
323 handleException();
324 }
325 check(1);
326}
327
328void Buffer::keysOld(const int keyCount, const int *const keys, const int bytes, const char *const buf) {
329 if (checkSpace((2 + keyCount) * MAXSIZE_PACK32 + bytes)) {
330 packInt(CODE_KEYS_OLD);
331 packInt(keyCount);
332 for (int i = 0; i < keyCount; ++i) {
333 packInt(keys[i]);
334 }
335 writeBytes(buf, bytes);
336 } else {
337 logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
338 handleException();
339 }
340 check(1);
341}
342
343void Buffer::format(const int length, const char *const format) {
344 if (checkSpace(MAXSIZE_PACK32 + length + 1)) {
345 packInt(CODE_FORMAT);
346 writeBytes(format, length + 1);
347 } else {
348 logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
349 handleException();
350 }
351 check(1);
352}
353
354void Buffer::maps(const int pid, const int tid, const char *const maps) {
355 const int mapsLen = strlen(maps) + 1;
356 if (checkSpace(3 * MAXSIZE_PACK32 + mapsLen)) {
357 packInt(CODE_MAPS);
358 packInt(pid);
359 packInt(tid);
360 writeBytes(maps, mapsLen);
361 } else {
362 logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
363 handleException();
364 }
365 check(1);
366}
367
368void Buffer::comm(const int pid, const int tid, const char *const image, const char *const comm) {
369 const int imageLen = strlen(image) + 1;
370 const int commLen = strlen(comm) + 1;
371 if (checkSpace(3 * MAXSIZE_PACK32 + imageLen + commLen)) {
372 packInt(CODE_COMM);
373 packInt(pid);
374 packInt(tid);
375 writeBytes(image, imageLen);
376 writeBytes(comm, commLen);
377 } else {
378 logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
379 handleException();
380 }
381 check(1);
382}
383
384void Buffer::setDone() {
385 mIsDone = true;
386 commit(0);
387}
388
389bool Buffer::isDone() const {
390 return mIsDone && mReadPos == mCommitPos && mCommitPos == mWritePos;
391}
diff --git a/tools/gator/daemon/Buffer.h b/tools/gator/daemon/Buffer.h
new file mode 100644
index 00000000000..2de1b97ac09
--- /dev/null
+++ b/tools/gator/daemon/Buffer.h
@@ -0,0 +1,102 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef BUFFER_H
10#define BUFFER_H
11
12#include <stdint.h>
13#include <semaphore.h>
14
15#include "k/perf_event.h"
16
17class Sender;
18
19enum {
20 FRAME_SUMMARY = 1,
21 FRAME_BLOCK_COUNTER = 5,
22 FRAME_EXTERNAL = 10,
23 FRAME_PERF_ATTRS = 11,
24 FRAME_PERF = 12,
25};
26
27class Buffer {
28public:
29 static const size_t MAXSIZE_PACK32 = 5;
30 static const size_t MAXSIZE_PACK64 = 10;
31
32 Buffer(int32_t core, int32_t buftype, const int size, sem_t *const readerSem);
33 ~Buffer();
34
35 void write(Sender *sender);
36
37 int bytesAvailable() const;
38 int contiguousSpaceAvailable() const;
39 void commit(const uint64_t time);
40 void check(const uint64_t time);
41
42 void frame();
43
44 // Summary messages
45 void summary(const int64_t timestamp, const int64_t uptime, const int64_t monotonicDelta, const char *const uname);
46 void coreName(const int core, const int cpuid, const char *const name);
47
48 // Block Counter messages
49 bool eventHeader(uint64_t curr_time);
50 bool eventTid(int tid);
51 void event(int32_t key, int32_t value);
52 void event64(int64_t key, int64_t value);
53
54 // Perf Attrs messages
55 void pea(const struct perf_event_attr *const pea, int key);
56 void keys(const int count, const __u64 *const ids, const int *const keys);
57 void keysOld(const int keyCount, const int *const keys, const int bytes, const char *const buf);
58 void format(const int length, const char *const format);
59 void maps(const int pid, const int tid, const char *const maps);
60 void comm(const int pid, const int tid, const char *const image, const char *const comm);
61
62 void setDone();
63 bool isDone() const;
64
65 // Prefer a new member to using these functions if possible
66 char *getWritePos() { return mBuf + mWritePos; }
67 void advanceWrite(int bytes) { mWritePos = (mWritePos + bytes) & /*mask*/(mSize - 1); }
68 static void packInt(char *const buf, const int size, int &writePos, int32_t x);
69 void packInt(int32_t x);
70 void packInt64(int64_t x);
71 void writeBytes(const void *const data, size_t count);
72 void writeString(const char *const str);
73
74 static void writeLEInt(unsigned char *buf, int v) {
75 buf[0] = (v >> 0) & 0xFF;
76 buf[1] = (v >> 8) & 0xFF;
77 buf[2] = (v >> 16) & 0xFF;
78 buf[3] = (v >> 24) & 0xFF;
79 }
80
81private:
82 bool commitReady() const;
83 bool checkSpace(int bytes);
84
85 const int32_t mCore;
86 const int32_t mBufType;
87 const int mSize;
88 int mReadPos;
89 int mWritePos;
90 int mCommitPos;
91 bool mAvailable;
92 bool mIsDone;
93 char *const mBuf;
94 uint64_t mCommitTime;
95 sem_t *const mReaderSem;
96
97 // Intentionally unimplemented
98 Buffer(const Buffer &);
99 Buffer &operator=(const Buffer &);
100};
101
102#endif // BUFFER_H
diff --git a/tools/gator/daemon/CapturedXML.cpp b/tools/gator/daemon/CapturedXML.cpp
new file mode 100644
index 00000000000..4a11415a00c
--- /dev/null
+++ b/tools/gator/daemon/CapturedXML.cpp
@@ -0,0 +1,144 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "CapturedXML.h"
10
11#include <stdlib.h>
12#include <string.h>
13#include <dirent.h>
14
15#include "SessionData.h"
16#include "Logging.h"
17#include "OlyUtility.h"
18
19CapturedXML::CapturedXML() {
20}
21
22CapturedXML::~CapturedXML() {
23}
24
25mxml_node_t* CapturedXML::getTree(bool includeTime) {
26 mxml_node_t *xml;
27 mxml_node_t *captured;
28 mxml_node_t *target;
29 int x;
30
31 xml = mxmlNewXML("1.0");
32
33 captured = mxmlNewElement(xml, "captured");
34 mxmlElementSetAttr(captured, "version", "1");
35 if (gSessionData->perf.isSetup()) {
36 mxmlElementSetAttr(captured, "type", "Perf");
37 }
38 mxmlElementSetAttrf(captured, "protocol", "%d", PROTOCOL_VERSION);
39 if (includeTime) { // Send the following only after the capture is complete
40 if (time(NULL) > 1267000000) { // If the time is reasonable (after Feb 23, 2010)
41 mxmlElementSetAttrf(captured, "created", "%lu", time(NULL)); // Valid until the year 2038
42 }
43 }
44
45 target = mxmlNewElement(captured, "target");
46 mxmlElementSetAttr(target, "name", gSessionData->mCoreName);
47 mxmlElementSetAttrf(target, "sample_rate", "%d", gSessionData->mSampleRate);
48 mxmlElementSetAttrf(target, "cores", "%d", gSessionData->mCores);
49 mxmlElementSetAttrf(target, "cpuid", "0x%x", gSessionData->mMaxCpuId);
50
51 if (!gSessionData->mOneShot && (gSessionData->mSampleRate > 0)) {
52 mxmlElementSetAttr(target, "supports_live", "yes");
53 }
54
55 if (gSessionData->mLocalCapture) {
56 mxmlElementSetAttr(target, "local_capture", "yes");
57 }
58
59 mxml_node_t *counters = NULL;
60 for (x = 0; x < MAX_PERFORMANCE_COUNTERS; x++) {
61 const Counter & counter = gSessionData->mCounters[x];
62 if (counter.isEnabled()) {
63 if (counters == NULL) {
64 counters = mxmlNewElement(captured, "counters");
65 }
66 mxml_node_t *const node = mxmlNewElement(counters, "counter");
67 mxmlElementSetAttrf(node, "key", "0x%x", counter.getKey());
68 mxmlElementSetAttr(node, "type", counter.getType());
69 if (counter.getEvent() != -1) {
70 mxmlElementSetAttrf(node, "event", "0x%x", counter.getEvent());
71 }
72 if (counter.getCount() > 0) {
73 mxmlElementSetAttrf(node, "count", "%d", counter.getCount());
74 }
75 if (counter.getCores() > 0) {
76 mxmlElementSetAttrf(node, "cores", "%d", counter.getCores());
77 }
78 }
79 }
80
81 return xml;
82}
83
84char* CapturedXML::getXML(bool includeTime) {
85 char* xml_string;
86 mxml_node_t *xml = getTree(includeTime);
87 xml_string = mxmlSaveAllocString(xml, mxmlWhitespaceCB);
88 mxmlDelete(xml);
89 return xml_string;
90}
91
92void CapturedXML::write(char* path) {
93 char file[PATH_MAX];
94
95 // Set full path
96 snprintf(file, PATH_MAX, "%s/captured.xml", path);
97
98 char* xml = getXML(true);
99 if (util->writeToDisk(file, xml) < 0) {
100 logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify the path.", file);
101 handleException();
102 }
103
104 free(xml);
105}
106
107// whitespace callback utility function used with mini-xml
108const char * mxmlWhitespaceCB(mxml_node_t *node, int loc) {
109 const char *name;
110
111 name = mxmlGetElement(node);
112
113 if (loc == MXML_WS_BEFORE_OPEN) {
114 // Single indentation
115 if (!strcmp(name, "target") || !strcmp(name, "counters"))
116 return("\n ");
117
118 // Double indentation
119 if (!strcmp(name, "counter"))
120 return("\n ");
121
122 // Avoid a carriage return on the first line of the xml file
123 if (!strncmp(name, "?xml", 4))
124 return(NULL);
125
126 // Default - no indentation
127 return("\n");
128 }
129
130 if (loc == MXML_WS_BEFORE_CLOSE) {
131 // No indentation
132 if (!strcmp(name, "captured"))
133 return("\n");
134
135 // Single indentation
136 if (!strcmp(name, "counters"))
137 return("\n ");
138
139 // Default - no carriage return
140 return(NULL);
141 }
142
143 return(NULL);
144}
diff --git a/tools/gator/daemon/CapturedXML.h b/tools/gator/daemon/CapturedXML.h
new file mode 100644
index 00000000000..ed08c44bc3f
--- /dev/null
+++ b/tools/gator/daemon/CapturedXML.h
@@ -0,0 +1,26 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef __CAPTURED_XML_H__
10#define __CAPTURED_XML_H__
11
12#include "mxml/mxml.h"
13
14class CapturedXML {
15public:
16 CapturedXML();
17 ~CapturedXML();
18 char* getXML(bool includeTime); // the string should be freed by the caller
19 void write(char* path);
20private:
21 mxml_node_t* getTree(bool includeTime);
22};
23
24const char * mxmlWhitespaceCB(mxml_node_t *node, int where);
25
26#endif //__CAPTURED_XML_H__
diff --git a/tools/gator/daemon/Child.cpp b/tools/gator/daemon/Child.cpp
new file mode 100644
index 00000000000..1901ecc6a72
--- /dev/null
+++ b/tools/gator/daemon/Child.cpp
@@ -0,0 +1,346 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "Child.h"
10
11#include <stdlib.h>
12#include <string.h>
13#include <signal.h>
14#include <unistd.h>
15#include <sys/prctl.h>
16
17#include "Logging.h"
18#include "CapturedXML.h"
19#include "SessionData.h"
20#include "LocalCapture.h"
21#include "Sender.h"
22#include "OlyUtility.h"
23#include "OlySocket.h"
24#include "StreamlineSetup.h"
25#include "ConfigurationXML.h"
26#include "Driver.h"
27#include "PerfSource.h"
28#include "DriverSource.h"
29#include "ExternalSource.h"
30#include "UserSpaceSource.h"
31
32static sem_t haltPipeline, senderThreadStarted, startProfile, senderSem; // Shared by Child and spawned threads
33static Source *primarySource = NULL;
34static Source *externalSource = NULL;
35static Source *userSpaceSource = NULL;
36static Sender* sender = NULL; // Shared by Child.cpp and spawned threads
37Child* child = NULL; // shared by Child.cpp and main.cpp
38
39extern void cleanUp();
40void handleException() {
41 if (child && child->numExceptions++ > 0) {
42 // it is possible one of the below functions itself can cause an exception, thus allow only one exception
43 logg->logMessage("Received multiple exceptions, terminating the child");
44 exit(1);
45 }
46 fprintf(stderr, "%s", logg->getLastError());
47
48 if (child && child->socket) {
49 if (sender) {
50 // send the error, regardless of the command sent by Streamline
51 sender->writeData(logg->getLastError(), strlen(logg->getLastError()), RESPONSE_ERROR);
52
53 // cannot close the socket before Streamline issues the command, so wait for the command before exiting
54 if (gSessionData->mWaitingOnCommand) {
55 char discard;
56 child->socket->receiveNBytes(&discard, 1);
57 }
58
59 // Ensure all data is flushed
60 child->socket->shutdownConnection();
61
62 // this indirectly calls close socket which will ensure the data has been sent
63 delete sender;
64 }
65 }
66
67 if (gSessionData->mLocalCapture)
68 cleanUp();
69
70 exit(1);
71}
72
73// CTRL C Signal Handler for child process
74static void child_handler(int signum) {
75 static bool beenHere = false;
76 if (beenHere == true) {
77 logg->logMessage("Gator is being forced to shut down.");
78 exit(1);
79 }
80 beenHere = true;
81 logg->logMessage("Gator is shutting down.");
82 if (signum == SIGALRM || !primarySource) {
83 exit(1);
84 } else {
85 child->endSession();
86 alarm(5); // Safety net in case endSession does not complete within 5 seconds
87 }
88}
89
90static void *durationThread(void *) {
91 prctl(PR_SET_NAME, (unsigned long)&"gatord-duration", 0, 0, 0);
92 sem_wait(&startProfile);
93 if (gSessionData->mSessionIsActive) {
94 // Time out after duration seconds
95 // Add a second for host-side filtering
96 sleep(gSessionData->mDuration + 1);
97 if (gSessionData->mSessionIsActive) {
98 logg->logMessage("Duration expired.");
99 child->endSession();
100 }
101 }
102 logg->logMessage("Exit duration thread");
103 return 0;
104}
105
106static void *stopThread(void *) {
107 OlySocket* socket = child->socket;
108
109 prctl(PR_SET_NAME, (unsigned long)&"gatord-stopper", 0, 0, 0);
110 while (gSessionData->mSessionIsActive) {
111 // This thread will stall until the APC_STOP or PING command is received over the socket or the socket is disconnected
112 unsigned char header[5];
113 const int result = socket->receiveNBytes((char*)&header, sizeof(header));
114 const char type = header[0];
115 const int length = (header[1] << 0) | (header[2] << 8) | (header[3] << 16) | (header[4] << 24);
116 if (result == -1) {
117 child->endSession();
118 } else if (result > 0) {
119 if ((type != COMMAND_APC_STOP) && (type != COMMAND_PING)) {
120 logg->logMessage("INVESTIGATE: Received unknown command type %d", type);
121 } else {
122 // verify a length of zero
123 if (length == 0) {
124 if (type == COMMAND_APC_STOP) {
125 logg->logMessage("Stop command received.");
126 child->endSession();
127 } else {
128 // Ping is used to make sure gator is alive and requires an ACK as the response
129 logg->logMessage("Ping command received.");
130 sender->writeData(NULL, 0, RESPONSE_ACK);
131 }
132 } else {
133 logg->logMessage("INVESTIGATE: Received stop command but with length = %d", length);
134 }
135 }
136 }
137 }
138
139 logg->logMessage("Exit stop thread");
140 return 0;
141}
142
143static void *senderThread(void *) {
144 char end_sequence[] = {RESPONSE_APC_DATA, 0, 0, 0, 0};
145
146 sem_post(&senderThreadStarted);
147 prctl(PR_SET_NAME, (unsigned long)&"gatord-sender", 0, 0, 0);
148 sem_wait(&haltPipeline);
149
150 while (!primarySource->isDone() ||
151 !externalSource->isDone() ||
152 (userSpaceSource != NULL && !userSpaceSource->isDone())) {
153 sem_wait(&senderSem);
154
155 primarySource->write(sender);
156 externalSource->write(sender);
157 if (userSpaceSource != NULL) {
158 userSpaceSource->write(sender);
159 }
160 }
161
162 // write end-of-capture sequence
163 if (!gSessionData->mLocalCapture) {
164 sender->writeData(end_sequence, sizeof(end_sequence), RESPONSE_APC_DATA);
165 }
166
167 logg->logMessage("Exit sender thread");
168 return 0;
169}
170
171Child::Child() {
172 initialization();
173 gSessionData->mLocalCapture = true;
174}
175
176Child::Child(OlySocket* sock, int conn) {
177 initialization();
178 socket = sock;
179 mNumConnections = conn;
180}
181
182Child::~Child() {
183}
184
185void Child::initialization() {
186 // Set up different handlers for signals
187 gSessionData->mSessionIsActive = true;
188 signal(SIGINT, child_handler);
189 signal(SIGTERM, child_handler);
190 signal(SIGABRT, child_handler);
191 signal(SIGALRM, child_handler);
192 socket = NULL;
193 numExceptions = 0;
194 mNumConnections = 0;
195
196 // Initialize semaphores
197 sem_init(&senderThreadStarted, 0, 0);
198 sem_init(&startProfile, 0, 0);
199 sem_init(&senderSem, 0, 0);
200}
201
202void Child::endSession() {
203 gSessionData->mSessionIsActive = false;
204 primarySource->interrupt();
205 externalSource->interrupt();
206 if (userSpaceSource != NULL) {
207 userSpaceSource->interrupt();
208 }
209 sem_post(&haltPipeline);
210}
211
212void Child::run() {
213 LocalCapture* localCapture = NULL;
214 pthread_t durationThreadID, stopThreadID, senderThreadID;
215
216 prctl(PR_SET_NAME, (unsigned long)&"gatord-child", 0, 0, 0);
217
218 // Disable line wrapping when generating xml files; carriage returns and indentation to be added manually
219 mxmlSetWrapMargin(0);
220
221 // Instantiate the Sender - must be done first, after which error messages can be sent
222 sender = new Sender(socket);
223
224 if (mNumConnections > 1) {
225 logg->logError(__FILE__, __LINE__, "Session already in progress");
226 handleException();
227 }
228
229 // Populate gSessionData with the configuration
230 { ConfigurationXML configuration; }
231
232 // Set up the driver; must be done after gSessionData->mPerfCounterType[] is populated
233 if (!gSessionData->perf.isSetup()) {
234 primarySource = new DriverSource(&senderSem, &startProfile);
235 } else {
236 primarySource = new PerfSource(&senderSem, &startProfile);
237 }
238
239 // Initialize all drivers
240 for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
241 driver->resetCounters();
242 }
243
244 // Set up counters using the associated driver's setup function
245 for (int i = 0; i < MAX_PERFORMANCE_COUNTERS; i++) {
246 Counter & counter = gSessionData->mCounters[i];
247 if (counter.isEnabled()) {
248 counter.getDriver()->setupCounter(counter);
249 }
250 }
251
252 // Start up and parse session xml
253 if (socket) {
254 // Respond to Streamline requests
255 StreamlineSetup ss(socket);
256 } else {
257 char* xmlString;
258 xmlString = util->readFromDisk(gSessionData->mSessionXMLPath);
259 if (xmlString == 0) {
260 logg->logError(__FILE__, __LINE__, "Unable to read session xml file: %s", gSessionData->mSessionXMLPath);
261 handleException();
262 }
263 gSessionData->parseSessionXML(xmlString);
264 localCapture = new LocalCapture();
265 localCapture->createAPCDirectory(gSessionData->mTargetPath);
266 localCapture->copyImages(gSessionData->mImages);
267 localCapture->write(xmlString);
268 sender->createDataFile(gSessionData->mAPCDir);
269 free(xmlString);
270 }
271
272 // Must be after session XML is parsed
273 if (!primarySource->prepare()) {
274 logg->logError(__FILE__, __LINE__, "Unable to prepare for capture");
275 handleException();
276 }
277
278 // Sender thread shall be halted until it is signaled for one shot mode
279 sem_init(&haltPipeline, 0, gSessionData->mOneShot ? 0 : 2);
280
281 // Create the duration, stop, and sender threads
282 bool thread_creation_success = true;
283 if (gSessionData->mDuration > 0 && pthread_create(&durationThreadID, NULL, durationThread, NULL)) {
284 thread_creation_success = false;
285 } else if (socket && pthread_create(&stopThreadID, NULL, stopThread, NULL)) {
286 thread_creation_success = false;
287 } else if (pthread_create(&senderThreadID, NULL, senderThread, NULL)) {
288 thread_creation_success = false;
289 }
290
291 externalSource = new ExternalSource(&senderSem);
292 if (!externalSource->prepare()) {
293 logg->logError(__FILE__, __LINE__, "Unable to prepare for capture");
294 handleException();
295 }
296 externalSource->start();
297
298 if (gSessionData->hwmon.countersEnabled() || gSessionData->fsDriver.countersEnabled()) {
299 userSpaceSource = new UserSpaceSource(&senderSem);
300 if (!userSpaceSource->prepare()) {
301 logg->logError(__FILE__, __LINE__, "Unable to prepare for capture");
302 handleException();
303 }
304 userSpaceSource->start();
305 }
306
307 if (!thread_creation_success) {
308 logg->logError(__FILE__, __LINE__, "Failed to create gator threads");
309 handleException();
310 }
311
312 // Wait until thread has started
313 sem_wait(&senderThreadStarted);
314
315 // Start profiling
316 primarySource->run();
317
318 if (userSpaceSource != NULL) {
319 userSpaceSource->join();
320 }
321 externalSource->join();
322
323 // Wait for the other threads to exit
324 pthread_join(senderThreadID, NULL);
325
326 // Shutting down the connection should break the stop thread which is stalling on the socket recv() function
327 if (socket) {
328 logg->logMessage("Waiting on stop thread");
329 socket->shutdownConnection();
330 pthread_join(stopThreadID, NULL);
331 }
332
333 // Write the captured xml file
334 if (gSessionData->mLocalCapture) {
335 CapturedXML capturedXML;
336 capturedXML.write(gSessionData->mAPCDir);
337 }
338
339 logg->logMessage("Profiling ended.");
340
341 delete userSpaceSource;
342 delete externalSource;
343 delete primarySource;
344 delete sender;
345 delete localCapture;
346}
diff --git a/tools/gator/daemon/Child.h b/tools/gator/daemon/Child.h
new file mode 100644
index 00000000000..a306a776081
--- /dev/null
+++ b/tools/gator/daemon/Child.h
@@ -0,0 +1,33 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef __CHILD_H__
10#define __CHILD_H__
11
12class OlySocket;
13
14class Child {
15public:
16 Child();
17 Child(OlySocket* sock, int numConnections);
18 ~Child();
19 void run();
20 OlySocket *socket;
21 void endSession();
22 int numExceptions;
23private:
24 int mNumConnections;
25
26 void initialization();
27
28 // Intentionally unimplemented
29 Child(const Child &);
30 Child &operator=(const Child &);
31};
32
33#endif //__CHILD_H__
diff --git a/tools/gator/daemon/Config.h b/tools/gator/daemon/Config.h
new file mode 100644
index 00000000000..6f5e2aae50e
--- /dev/null
+++ b/tools/gator/daemon/Config.h
@@ -0,0 +1,17 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef CONFIG_H
10#define CONFIG_H
11
12#define ARRAY_LENGTH(A) static_cast<int>(sizeof(A)/sizeof((A)[0]))
13
14#define MAX_PERFORMANCE_COUNTERS 50
15#define NR_CPUS 16
16
17#endif // CONFIG_H
diff --git a/tools/gator/daemon/ConfigurationXML.cpp b/tools/gator/daemon/ConfigurationXML.cpp
new file mode 100644
index 00000000000..6590dd38919
--- /dev/null
+++ b/tools/gator/daemon/ConfigurationXML.cpp
@@ -0,0 +1,217 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "ConfigurationXML.h"
10
11#include <string.h>
12#include <stdlib.h>
13#include <dirent.h>
14
15#include "Driver.h"
16#include "Logging.h"
17#include "OlyUtility.h"
18#include "SessionData.h"
19
20static const char* ATTR_COUNTER = "counter";
21static const char* ATTR_REVISION = "revision";
22static const char* ATTR_EVENT = "event";
23static const char* ATTR_COUNT = "count";
24static const char* ATTR_CORES = "cores";
25
26ConfigurationXML::ConfigurationXML() {
27 const char * configuration_xml;
28 unsigned int configuration_xml_len;
29 getDefaultConfigurationXml(configuration_xml, configuration_xml_len);
30
31 char path[PATH_MAX];
32
33 getPath(path);
34 mConfigurationXML = util->readFromDisk(path);
35
36 for (int retryCount = 0; retryCount < 2; ++retryCount) {
37 if (mConfigurationXML == NULL) {
38 logg->logMessage("Unable to locate configuration.xml, using default in binary");
39 // null-terminate configuration_xml
40 mConfigurationXML = (char*)malloc(configuration_xml_len + 1);
41 memcpy(mConfigurationXML, (const void*)configuration_xml, configuration_xml_len);
42 mConfigurationXML[configuration_xml_len] = 0;
43 }
44
45 int ret = parse(mConfigurationXML);
46 if (ret == 1) {
47 remove();
48
49 // Free the current configuration and reload
50 free((void*)mConfigurationXML);
51 mConfigurationXML = NULL;
52 continue;
53 }
54
55 break;
56 }
57
58 validate();
59}
60
61ConfigurationXML::~ConfigurationXML() {
62 if (mConfigurationXML) {
63 free((void*)mConfigurationXML);
64 }
65}
66
67int ConfigurationXML::parse(const char* configurationXML) {
68 mxml_node_t *tree, *node;
69 int ret;
70
71 // clear counter overflow
72 gSessionData->mCounterOverflow = 0;
73 gSessionData->mIsEBS = false;
74 mIndex = 0;
75
76 // disable all counters prior to parsing the configuration xml
77 for (int i = 0; i < MAX_PERFORMANCE_COUNTERS; i++) {
78 gSessionData->mCounters[i].setEnabled(false);
79 }
80
81 tree = mxmlLoadString(NULL, configurationXML, MXML_NO_CALLBACK);
82
83 node = mxmlGetFirstChild(tree);
84 while (node && mxmlGetType(node) != MXML_ELEMENT)
85 node = mxmlWalkNext(node, tree, MXML_NO_DESCEND);
86
87 ret = configurationsTag(node);
88
89 node = mxmlGetFirstChild(node);
90 while (node) {
91 if (mxmlGetType(node) != MXML_ELEMENT) {
92 node = mxmlWalkNext(node, tree, MXML_NO_DESCEND);
93 continue;
94 }
95 configurationTag(node);
96 node = mxmlWalkNext(node, tree, MXML_NO_DESCEND);
97 }
98
99 mxmlDelete(tree);
100
101 return ret;
102}
103
104void ConfigurationXML::validate(void) {
105 for (int i = 0; i < MAX_PERFORMANCE_COUNTERS; i++) {
106 const Counter & counter = gSessionData->mCounters[i];
107 if (counter.isEnabled()) {
108 if (strcmp(counter.getType(), "") == 0) {
109 logg->logError(__FILE__, __LINE__, "Invalid required attribute in configuration.xml:\n counter=\"%s\"\n event=%d\n", counter.getType(), counter.getEvent());
110 handleException();
111 }
112
113 // iterate through the remaining enabled performance counters
114 for (int j = i + 1; j < MAX_PERFORMANCE_COUNTERS; j++) {
115 const Counter & counter2 = gSessionData->mCounters[j];
116 if (counter2.isEnabled()) {
117 // check if the types are the same
118 if (strcmp(counter.getType(), counter2.getType()) == 0) {
119 logg->logError(__FILE__, __LINE__, "Duplicate performance counter type in configuration.xml: %s", counter.getType());
120 handleException();
121 }
122 }
123 }
124 }
125 }
126}
127
128#define CONFIGURATION_REVISION 3
129int ConfigurationXML::configurationsTag(mxml_node_t *node) {
130 const char* revision_string;
131
132 revision_string = mxmlElementGetAttr(node, ATTR_REVISION);
133 if (!revision_string) {
134 return 1; //revision issue;
135 }
136
137 int revision = strtol(revision_string, NULL, 10);
138 if (revision < CONFIGURATION_REVISION) {
139 return 1; // revision issue
140 }
141
142 // A revision >= CONFIGURATION_REVISION is okay
143 // Greater than can occur when Streamline is newer than gator
144
145 return 0;
146}
147
148void ConfigurationXML::configurationTag(mxml_node_t *node) {
149 // handle all other performance counters
150 if (mIndex >= MAX_PERFORMANCE_COUNTERS) {
151 mIndex++;
152 gSessionData->mCounterOverflow = mIndex;
153 return;
154 }
155
156 // read attributes
157 Counter & counter = gSessionData->mCounters[mIndex];
158 counter.clear();
159 if (mxmlElementGetAttr(node, ATTR_COUNTER)) counter.setType(mxmlElementGetAttr(node, ATTR_COUNTER));
160 if (mxmlElementGetAttr(node, ATTR_EVENT)) counter.setEvent(strtol(mxmlElementGetAttr(node, ATTR_EVENT), NULL, 16));
161 if (mxmlElementGetAttr(node, ATTR_COUNT)) counter.setCount(strtol(mxmlElementGetAttr(node, ATTR_COUNT), NULL, 10));
162 if (mxmlElementGetAttr(node, ATTR_CORES)) counter.setCores(strtol(mxmlElementGetAttr(node, ATTR_CORES), NULL, 10));
163 if (counter.getCount() > 0) {
164 gSessionData->mIsEBS = true;
165 }
166 counter.setEnabled(true);
167
168 // Associate a driver with each counter
169 for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
170 if (driver->claimCounter(counter)) {
171 if (counter.getDriver() != NULL) {
172 logg->logError(__FILE__, __LINE__, "More than one driver has claimed %s:%i", counter.getType(), counter.getEvent());
173 handleException();
174 }
175 counter.setDriver(driver);
176 }
177 }
178
179 // If no driver is associated with the counter, disable it
180 if (counter.getDriver() == NULL) {
181 logg->logMessage("No driver has claimed %s:%i", counter.getType(), counter.getEvent());
182 counter.setEnabled(false);
183 }
184
185 if (counter.isEnabled()) {
186 // update counter index
187 mIndex++;
188 }
189}
190
191void ConfigurationXML::getDefaultConfigurationXml(const char * & xml, unsigned int & len) {
192#include "defaults_xml.h" // defines and initializes char defaults_xml[] and int defaults_xml_len
193 xml = (const char *)defaults_xml;
194 len = defaults_xml_len;
195}
196
197void ConfigurationXML::getPath(char* path) {
198 if (gSessionData->mConfigurationXMLPath) {
199 strncpy(path, gSessionData->mConfigurationXMLPath, PATH_MAX);
200 } else {
201 if (util->getApplicationFullPath(path, PATH_MAX) != 0) {
202 logg->logMessage("Unable to determine the full path of gatord, the cwd will be used");
203 }
204 strncat(path, "configuration.xml", PATH_MAX - strlen(path) - 1);
205 }
206}
207
208void ConfigurationXML::remove() {
209 char path[PATH_MAX];
210 getPath(path);
211
212 if (::remove(path) != 0) {
213 logg->logError(__FILE__, __LINE__, "Invalid configuration.xml file detected and unable to delete it. To resolve, delete configuration.xml on disk");
214 handleException();
215 }
216 logg->logMessage("Invalid configuration.xml file detected and removed");
217}
diff --git a/tools/gator/daemon/ConfigurationXML.h b/tools/gator/daemon/ConfigurationXML.h
new file mode 100644
index 00000000000..efa415e508b
--- /dev/null
+++ b/tools/gator/daemon/ConfigurationXML.h
@@ -0,0 +1,38 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef COUNTERS_H
10#define COUNTERS_H
11
12#include "mxml/mxml.h"
13
14class ConfigurationXML {
15public:
16 static void getDefaultConfigurationXml(const char * & xml, unsigned int & len);
17 static void getPath(char* path);
18 static void remove();
19
20 ConfigurationXML();
21 ~ConfigurationXML();
22 const char* getConfigurationXML() {return mConfigurationXML;}
23 void validate(void);
24
25private:
26 char* mConfigurationXML;
27 int mIndex;
28
29 int parse(const char* xmlFile);
30 int configurationsTag(mxml_node_t *node);
31 void configurationTag(mxml_node_t *node);
32
33 // Intentionally unimplemented
34 ConfigurationXML(const ConfigurationXML &);
35 ConfigurationXML &operator=(const ConfigurationXML &);
36};
37
38#endif // COUNTERS_H
diff --git a/tools/gator/daemon/Counter.h b/tools/gator/daemon/Counter.h
new file mode 100644
index 00000000000..5202aa04636
--- /dev/null
+++ b/tools/gator/daemon/Counter.h
@@ -0,0 +1,65 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef COUNTER_H
10#define COUNTER_H
11
12#include <string.h>
13
14class Driver;
15
16class Counter {
17public:
18 static const size_t MAX_STRING_LEN = 80;
19 static const size_t MAX_DESCRIPTION_LEN = 400;
20
21 Counter () {
22 clear();
23 }
24
25 void clear () {
26 mType[0] = '\0';
27 mEnabled = false;
28 mEvent = -1;
29 mCount = 0;
30 mCores = -1;
31 mKey = 0;
32 mDriver = NULL;
33 }
34
35 void setType(const char *const type) { strncpy(mType, type, sizeof(mType)); mType[sizeof(mType) - 1] = '\0'; }
36 void setEnabled(const bool enabled) { mEnabled = enabled; }
37 void setEvent(const int event) { mEvent = event; }
38 void setCount(const int count) { mCount = count; }
39 void setCores(const int cores) { mCores = cores; }
40 void setKey(const int key) { mKey = key; }
41 void setDriver(Driver *const driver) { mDriver = driver; }
42
43 const char *getType() const { return mType;}
44 bool isEnabled() const { return mEnabled; }
45 int getEvent() const { return mEvent; }
46 int getCount() const { return mCount; }
47 int getCores() const { return mCores; }
48 int getKey() const { return mKey; }
49 Driver *getDriver() const { return mDriver; }
50
51private:
52 // Intentionally unimplemented
53 Counter(const Counter &);
54 Counter & operator=(const Counter &);
55
56 char mType[MAX_STRING_LEN];
57 bool mEnabled;
58 int mEvent;
59 int mCount;
60 int mCores;
61 int mKey;
62 Driver *mDriver;
63};
64
65#endif // COUNTER_H
diff --git a/tools/gator/daemon/Driver.cpp b/tools/gator/daemon/Driver.cpp
new file mode 100644
index 00000000000..09e04016291
--- /dev/null
+++ b/tools/gator/daemon/Driver.cpp
@@ -0,0 +1,15 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "Driver.h"
10
11Driver *Driver::head = NULL;
12
13Driver::Driver() : next(head) {
14 head = this;
15}
diff --git a/tools/gator/daemon/Driver.h b/tools/gator/daemon/Driver.h
new file mode 100644
index 00000000000..e5ed7b6c129
--- /dev/null
+++ b/tools/gator/daemon/Driver.h
@@ -0,0 +1,48 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef DRIVER_H
10#define DRIVER_H
11
12#include "mxml/mxml.h"
13
14class Counter;
15
16class Driver {
17public:
18 static Driver *getHead() { return head; }
19
20 virtual ~Driver() {}
21
22 // Returns true if this driver can manage the counter
23 virtual bool claimCounter(const Counter &counter) const = 0;
24 // Clears and disables all counters
25 virtual void resetCounters() = 0;
26 // Enables and prepares the counter for capture
27 virtual void setupCounter(Counter &counter) = 0;
28
29 // Emits available counters
30 virtual int writeCounters(mxml_node_t *root) const = 0;
31 // Emits possible dynamically generated events/counters
32 virtual void writeEvents(mxml_node_t *) const {}
33
34 Driver *getNext() const { return next; }
35
36protected:
37 Driver ();
38
39private:
40 static Driver *head;
41 Driver *next;
42
43 // Intentionally unimplemented
44 Driver(const Driver &);
45 Driver &operator=(const Driver &);
46};
47
48#endif // DRIVER_H
diff --git a/tools/gator/daemon/DriverSource.cpp b/tools/gator/daemon/DriverSource.cpp
new file mode 100644
index 00000000000..11d3095ef6d
--- /dev/null
+++ b/tools/gator/daemon/DriverSource.cpp
@@ -0,0 +1,321 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#define __STDC_FORMAT_MACROS
10
11#include "DriverSource.h"
12
13#include <fcntl.h>
14#include <inttypes.h>
15#include <sys/prctl.h>
16#include <unistd.h>
17
18#include "Buffer.h"
19#include "Child.h"
20#include "DynBuf.h"
21#include "Fifo.h"
22#include "Logging.h"
23#include "Proc.h"
24#include "Sender.h"
25#include "SessionData.h"
26
27extern Child *child;
28
29DriverSource::DriverSource(sem_t *senderSem, sem_t *startProfile) : mBuffer(NULL), mFifo(NULL), mSenderSem(senderSem), mStartProfile(startProfile), mBufferSize(0), mBufferFD(0), mLength(1) {
30 int driver_version = 0;
31
32 mBuffer = new Buffer(0, FRAME_PERF_ATTRS, 4*1024*1024, senderSem);
33 if (readIntDriver("/dev/gator/version", &driver_version) == -1) {
34 logg->logError(__FILE__, __LINE__, "Error reading gator driver version");
35 handleException();
36 }
37
38 // Verify the driver version matches the daemon version
39 if (driver_version != PROTOCOL_VERSION) {
40 if ((driver_version > PROTOCOL_DEV) || (PROTOCOL_VERSION > PROTOCOL_DEV)) {
41 // One of the mismatched versions is development version
42 logg->logError(__FILE__, __LINE__,
43 "DEVELOPMENT BUILD MISMATCH: gator driver version \"%d\" is not in sync with gator daemon version \"%d\".\n"
44 ">> The following must be synchronized from engineering repository:\n"
45 ">> * gator driver\n"
46 ">> * gator daemon\n"
47 ">> * Streamline", driver_version, PROTOCOL_VERSION);
48 handleException();
49 } else {
50 // Release version mismatch
51 logg->logError(__FILE__, __LINE__,
52 "gator driver version \"%d\" is different than gator daemon version \"%d\".\n"
53 ">> Please upgrade the driver and daemon to the latest versions.", driver_version, PROTOCOL_VERSION);
54 handleException();
55 }
56 }
57
58 int enable = -1;
59 if (readIntDriver("/dev/gator/enable", &enable) != 0 || enable != 0) {
60 logg->logError(__FILE__, __LINE__, "Driver already enabled, possibly a session is already in progress.");
61 handleException();
62 }
63
64 readIntDriver("/dev/gator/cpu_cores", &gSessionData->mCores);
65 if (gSessionData->mCores == 0) {
66 gSessionData->mCores = 1;
67 }
68
69 if (readIntDriver("/dev/gator/buffer_size", &mBufferSize) || mBufferSize <= 0) {
70 logg->logError(__FILE__, __LINE__, "Unable to read the driver buffer size");
71 handleException();
72 }
73}
74
75DriverSource::~DriverSource() {
76 delete mFifo;
77
78 // Write zero for safety, as a zero should have already been written
79 writeDriver("/dev/gator/enable", "0");
80
81 // Calls event_buffer_release in the driver
82 if (mBufferFD) {
83 close(mBufferFD);
84 }
85}
86
87bool DriverSource::prepare() {
88 // Create user-space buffers, add 5 to the size to account for the 1-byte type and 4-byte length
89 logg->logMessage("Created %d MB collector buffer with a %d-byte ragged end", gSessionData->mTotalBufferSize, mBufferSize);
90 mFifo = new Fifo(mBufferSize + 5, gSessionData->mTotalBufferSize*1024*1024, mSenderSem);
91
92 return true;
93}
94
95void DriverSource::bootstrapThread() {
96 prctl(PR_SET_NAME, (unsigned long)&"gatord-bootstrap", 0, 0, 0);
97
98 DynBuf printb;
99 DynBuf b1;
100 DynBuf b2;
101 DynBuf b3;
102
103 if (!readProc(mBuffer, false, &printb, &b1, &b2, &b3)) {
104 logg->logMessage("%s(%s:%i): readProc failed", __FUNCTION__, __FILE__, __LINE__);
105 handleException();
106 }
107
108 mBuffer->commit(1);
109 mBuffer->setDone();
110}
111
112void *DriverSource::bootstrapThreadStatic(void *arg) {
113 static_cast<DriverSource *>(arg)->bootstrapThread();
114 return NULL;
115}
116
117void DriverSource::run() {
118 // Get the initial pointer to the collect buffer
119 char *collectBuffer = mFifo->start();
120 int bytesCollected = 0;
121
122 logg->logMessage("********** Profiling started **********");
123
124 // Set the maximum backtrace depth
125 if (writeReadDriver("/dev/gator/backtrace_depth", &gSessionData->mBacktraceDepth)) {
126 logg->logError(__FILE__, __LINE__, "Unable to set the driver backtrace depth");
127 handleException();
128 }
129
130 // open the buffer which calls userspace_buffer_open() in the driver
131 mBufferFD = open("/dev/gator/buffer", O_RDONLY);
132 if (mBufferFD < 0) {
133 logg->logError(__FILE__, __LINE__, "The gator driver did not set up properly. Please view the linux console or dmesg log for more information on the failure.");
134 handleException();
135 }
136
137 // set the tick rate of the profiling timer
138 if (writeReadDriver("/dev/gator/tick", &gSessionData->mSampleRate) != 0) {
139 logg->logError(__FILE__, __LINE__, "Unable to set the driver tick");
140 handleException();
141 }
142
143 // notify the kernel of the response type
144 int response_type = gSessionData->mLocalCapture ? 0 : RESPONSE_APC_DATA;
145 if (writeDriver("/dev/gator/response_type", response_type)) {
146 logg->logError(__FILE__, __LINE__, "Unable to write the response type");
147 handleException();
148 }
149
150 // Set the live rate
151 if (writeReadDriver("/dev/gator/live_rate", &gSessionData->mLiveRate)) {
152 logg->logError(__FILE__, __LINE__, "Unable to set the driver live rate");
153 handleException();
154 }
155
156 logg->logMessage("Start the driver");
157
158 // This command makes the driver start profiling by calling gator_op_start() in the driver
159 if (writeDriver("/dev/gator/enable", "1") != 0) {
160 logg->logError(__FILE__, __LINE__, "The gator driver did not start properly. Please view the linux console or dmesg log for more information on the failure.");
161 handleException();
162 }
163
164 lseek(mBufferFD, 0, SEEK_SET);
165
166 sem_post(mStartProfile);
167
168 pthread_t bootstrapThreadID;
169 if (pthread_create(&bootstrapThreadID, NULL, bootstrapThreadStatic, this) != 0) {
170 logg->logError(__FILE__, __LINE__, "Unable to start the gator_bootstrap thread");
171 handleException();
172 }
173
174 // Collect Data
175 do {
176 // This command will stall until data is received from the driver
177 // Calls event_buffer_read in the driver
178 errno = 0;
179 bytesCollected = read(mBufferFD, collectBuffer, mBufferSize);
180
181 // If read() returned due to an interrupt signal, re-read to obtain the last bit of collected data
182 if (bytesCollected == -1 && errno == EINTR) {
183 bytesCollected = read(mBufferFD, collectBuffer, mBufferSize);
184 }
185
186 // return the total bytes written
187 logg->logMessage("Driver read of %d bytes", bytesCollected);
188
189 // In one shot mode, stop collection once all the buffers are filled
190 if (gSessionData->mOneShot && gSessionData->mSessionIsActive) {
191 if (bytesCollected == -1 || mFifo->willFill(bytesCollected)) {
192 logg->logMessage("One shot");
193 child->endSession();
194 }
195 }
196 collectBuffer = mFifo->write(bytesCollected);
197 } while (bytesCollected > 0);
198
199 logg->logMessage("Exit collect data loop");
200
201 pthread_join(bootstrapThreadID, NULL);
202}
203
204void DriverSource::interrupt() {
205 // This command should cause the read() function in collect() to return and stop the driver from profiling
206 if (writeDriver("/dev/gator/enable", "0") != 0) {
207 logg->logMessage("Stopping kernel failed");
208 }
209}
210
211bool DriverSource::isDone() {
212 return mLength <= 0 && (mBuffer == NULL || mBuffer->isDone());
213}
214
215void DriverSource::write(Sender *sender) {
216 char *data = mFifo->read(&mLength);
217 if (data != NULL) {
218 sender->writeData(data, mLength, RESPONSE_APC_DATA);
219 mFifo->release();
220 // Assume the summary packet is in the first block received from the driver
221 gSessionData->mSentSummary = true;
222 }
223 if (mBuffer != NULL && !mBuffer->isDone()) {
224 mBuffer->write(sender);
225 if (mBuffer->isDone()) {
226 Buffer *buf = mBuffer;
227 mBuffer = NULL;
228 delete buf;
229 }
230 }
231}
232
233int DriverSource::readIntDriver(const char *fullpath, int *value) {
234 char data[40]; // Sufficiently large to hold any integer
235 const int fd = open(fullpath, O_RDONLY);
236 if (fd < 0) {
237 return -1;
238 }
239
240 const ssize_t bytes = read(fd, data, sizeof(data) - 1);
241 close(fd);
242 if (bytes < 0) {
243 return -1;
244 }
245 data[bytes] = '\0';
246
247 char *endptr;
248 errno = 0;
249 *value = strtol(data, &endptr, 10);
250 if (errno != 0 || *endptr != '\n') {
251 logg->logMessage("Invalid value in file %s", fullpath);
252 return -1;
253 }
254
255 return 0;
256}
257
258int DriverSource::readInt64Driver(const char *fullpath, int64_t *value) {
259 char data[40]; // Sufficiently large to hold any integer
260 const int fd = open(fullpath, O_RDONLY);
261 if (fd < 0) {
262 return -1;
263 }
264
265 const ssize_t bytes = read(fd, data, sizeof(data) - 1);
266 close(fd);
267 if (bytes < 0) {
268 return -1;
269 }
270 data[bytes] = '\0';
271
272 char *endptr;
273 errno = 0;
274 *value = strtoll(data, &endptr, 10);
275 if (errno != 0 || (*endptr != '\n' && *endptr != '\0')) {
276 logg->logMessage("Invalid value in file %s", fullpath);
277 return -1;
278 }
279
280 return 0;
281}
282
283int DriverSource::writeDriver(const char *fullpath, const char *data) {
284 int fd = open(fullpath, O_WRONLY);
285 if (fd < 0) {
286 return -1;
287 }
288 if (::write(fd, data, strlen(data)) < 0) {
289 close(fd);
290 logg->logMessage("Opened but could not write to %s", fullpath);
291 return -1;
292 }
293 close(fd);
294 return 0;
295}
296
297int DriverSource::writeDriver(const char *path, int value) {
298 char data[40]; // Sufficiently large to hold any integer
299 snprintf(data, sizeof(data), "%d", value);
300 return writeDriver(path, data);
301}
302
303int DriverSource::writeDriver(const char *path, int64_t value) {
304 char data[40]; // Sufficiently large to hold any integer
305 snprintf(data, sizeof(data), "%" PRIi64, value);
306 return writeDriver(path, data);
307}
308
309int DriverSource::writeReadDriver(const char *path, int *value) {
310 if (writeDriver(path, *value) || readIntDriver(path, value)) {
311 return -1;
312 }
313 return 0;
314}
315
316int DriverSource::writeReadDriver(const char *path, int64_t *value) {
317 if (writeDriver(path, *value) || readInt64Driver(path, value)) {
318 return -1;
319 }
320 return 0;
321}
diff --git a/tools/gator/daemon/DriverSource.h b/tools/gator/daemon/DriverSource.h
new file mode 100644
index 00000000000..ec27b0815bb
--- /dev/null
+++ b/tools/gator/daemon/DriverSource.h
@@ -0,0 +1,57 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef DRIVERSOURCE_H
10#define DRIVERSOURCE_H
11
12#include <semaphore.h>
13#include <stdint.h>
14
15#include "Source.h"
16
17class Buffer;
18class Fifo;
19
20class DriverSource : public Source {
21public:
22 DriverSource(sem_t *senderSem, sem_t *startProfile);
23 ~DriverSource();
24
25 bool prepare();
26 void run();
27 void interrupt();
28
29 bool isDone();
30 void write(Sender *sender);
31
32 static int readIntDriver(const char *fullpath, int *value);
33 static int readInt64Driver(const char *fullpath, int64_t *value);
34 static int writeDriver(const char *fullpath, const char *data);
35 static int writeDriver(const char *path, int value);
36 static int writeDriver(const char *path, int64_t value);
37 static int writeReadDriver(const char *path, int *value);
38 static int writeReadDriver(const char *path, int64_t *value);
39
40private:
41 static void *bootstrapThreadStatic(void *arg);
42 void bootstrapThread();
43
44 Buffer *mBuffer;
45 Fifo *mFifo;
46 sem_t *const mSenderSem;
47 sem_t *const mStartProfile;
48 int mBufferSize;
49 int mBufferFD;
50 int mLength;
51
52 // Intentionally unimplemented
53 DriverSource(const DriverSource &);
54 DriverSource &operator=(const DriverSource &);
55};
56
57#endif // DRIVERSOURCE_H
diff --git a/tools/gator/daemon/DynBuf.cpp b/tools/gator/daemon/DynBuf.cpp
new file mode 100644
index 00000000000..6f92b336ae1
--- /dev/null
+++ b/tools/gator/daemon/DynBuf.cpp
@@ -0,0 +1,139 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "DynBuf.h"
10
11#include <errno.h>
12#include <fcntl.h>
13#include <stdarg.h>
14#include <stdio.h>
15#include <unistd.h>
16
17#include "Logging.h"
18
19// Pick an aggressive size as buffer is primarily used for disk IO
20#define MIN_BUFFER_FREE (1 << 12)
21
22int DynBuf::resize(const size_t minCapacity) {
23 size_t scaledCapacity = 2 * capacity;
24 if (scaledCapacity < minCapacity) {
25 scaledCapacity = minCapacity;
26 }
27 if (scaledCapacity < 2 * MIN_BUFFER_FREE) {
28 scaledCapacity = 2 * MIN_BUFFER_FREE;
29 }
30 capacity = scaledCapacity;
31
32 buf = static_cast<char *>(realloc(buf, capacity));
33 if (buf == NULL) {
34 return -errno;
35 }
36
37 return 0;
38}
39
40bool DynBuf::read(const char *const path) {
41 int result = false;
42
43 const int fd = open(path, O_RDONLY);
44 if (fd < 0) {
45 logg->logMessage("%s(%s:%i): open failed", __FUNCTION__, __FILE__, __LINE__);
46 return false;
47 }
48
49 length = 0;
50
51 for (;;) {
52 const size_t minCapacity = length + MIN_BUFFER_FREE + 1;
53 if (capacity < minCapacity) {
54 if (resize(minCapacity) != 0) {
55 logg->logMessage("%s(%s:%i): DynBuf::resize failed", __FUNCTION__, __FILE__, __LINE__);
56 goto fail;
57 }
58 }
59
60 const ssize_t bytes = ::read(fd, buf + length, capacity - length - 1);
61 if (bytes < 0) {
62 logg->logMessage("%s(%s:%i): read failed", __FUNCTION__, __FILE__, __LINE__);
63 goto fail;
64 } else if (bytes == 0) {
65 break;
66 }
67 length += bytes;
68 }
69
70 buf[length] = '\0';
71 result = true;
72
73 fail:
74 close(fd);
75
76 return result;
77}
78
79int DynBuf::readlink(const char *const path) {
80 ssize_t bytes = MIN_BUFFER_FREE;
81
82 for (;;) {
83 if (static_cast<size_t>(bytes) >= capacity) {
84 const int err = resize(2 * bytes);
85 if (err != 0) {
86 return err;
87 }
88 }
89 bytes = ::readlink(path, buf, capacity);
90 if (bytes < 0) {
91 return -errno;
92 } else if (static_cast<size_t>(bytes) < capacity) {
93 break;
94 }
95 }
96
97 length = bytes;
98 buf[bytes] = '\0';
99
100 return 0;
101}
102
103bool DynBuf::printf(const char *format, ...) {
104 va_list ap;
105
106 if (capacity <= 0) {
107 if (resize(2 * MIN_BUFFER_FREE) != 0) {
108 logg->logMessage("%s(%s:%i): DynBuf::resize failed", __FUNCTION__, __FILE__, __LINE__);
109 return false;
110 }
111 }
112
113 va_start(ap, format);
114 int bytes = vsnprintf(buf, capacity, format, ap);
115 va_end(ap);
116 if (bytes < 0) {
117 logg->logMessage("%s(%s:%i): fsnprintf failed", __FUNCTION__, __FILE__, __LINE__);
118 return false;
119 }
120
121 if (static_cast<size_t>(bytes) > capacity) {
122 if (resize(bytes + 1) != 0) {
123 logg->logMessage("%s(%s:%i): DynBuf::resize failed", __FUNCTION__, __FILE__, __LINE__);
124 return false;
125 }
126
127 va_start(ap, format);
128 bytes = vsnprintf(buf, capacity, format, ap);
129 va_end(ap);
130 if (bytes < 0) {
131 logg->logMessage("%s(%s:%i): fsnprintf failed", __FUNCTION__, __FILE__, __LINE__);
132 return false;
133 }
134 }
135
136 length = bytes;
137
138 return true;
139}
diff --git a/tools/gator/daemon/DynBuf.h b/tools/gator/daemon/DynBuf.h
new file mode 100644
index 00000000000..2f4554ab2e4
--- /dev/null
+++ b/tools/gator/daemon/DynBuf.h
@@ -0,0 +1,52 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef DYNBUF_H
10#define DYNBUF_H
11
12#include <stdlib.h>
13
14class DynBuf {
15public:
16 DynBuf() : capacity(0), length(0), buf(NULL) {}
17 ~DynBuf() {
18 reset();
19 }
20
21 inline void reset() {
22 capacity = 0;
23 length = 0;
24 if (buf != NULL) {
25 free(buf);
26 buf = NULL;
27 }
28 }
29
30 bool read(const char *const path);
31 // On error instead of printing the error and returning false, this returns -errno
32 int readlink(const char *const path);
33 __attribute__ ((format(printf, 2, 3)))
34 bool printf(const char *format, ...);
35
36 size_t getLength() const { return length; }
37 const char *getBuf() const { return buf; }
38 char *getBuf() { return buf; }
39
40private:
41 int resize(const size_t minCapacity);
42
43 size_t capacity;
44 size_t length;
45 char *buf;
46
47 // Intentionally undefined
48 DynBuf(const DynBuf &);
49 DynBuf &operator=(const DynBuf &);
50};
51
52#endif // DYNBUF_H
diff --git a/tools/gator/daemon/EventsXML.cpp b/tools/gator/daemon/EventsXML.cpp
new file mode 100644
index 00000000000..cf0192ef671
--- /dev/null
+++ b/tools/gator/daemon/EventsXML.cpp
@@ -0,0 +1,76 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "EventsXML.h"
10
11#include "CapturedXML.h"
12#include "Logging.h"
13#include "OlyUtility.h"
14#include "SessionData.h"
15
16mxml_node_t *EventsXML::getTree() {
17#include "events_xml.h" // defines and initializes char events_xml[] and int events_xml_len
18 char path[PATH_MAX];
19 mxml_node_t *xml;
20 FILE *fl;
21
22 // Avoid unused variable warning
23 (void)events_xml_len;
24
25 // Load the provided or default events xml
26 if (gSessionData->mEventsXMLPath) {
27 strncpy(path, gSessionData->mEventsXMLPath, PATH_MAX);
28 } else {
29 util->getApplicationFullPath(path, PATH_MAX);
30 strncat(path, "events.xml", PATH_MAX - strlen(path) - 1);
31 }
32 fl = fopen(path, "r");
33 if (fl) {
34 xml = mxmlLoadFile(NULL, fl, MXML_NO_CALLBACK);
35 fclose(fl);
36 } else {
37 logg->logMessage("Unable to locate events.xml, using default");
38 xml = mxmlLoadString(NULL, (const char *)events_xml, MXML_NO_CALLBACK);
39 }
40
41 return xml;
42}
43
44char *EventsXML::getXML() {
45 mxml_node_t *xml = getTree();
46
47 // Add dynamic events from the drivers
48 mxml_node_t *events = mxmlFindElement(xml, xml, "events", NULL, NULL, MXML_DESCEND);
49 if (!events) {
50 logg->logMessage("Unable to find <events> node in the events.xml");
51 handleException();
52 }
53 for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
54 driver->writeEvents(events);
55 }
56
57 char *string = mxmlSaveAllocString(xml, mxmlWhitespaceCB);
58 mxmlDelete(xml);
59
60 return string;
61}
62
63void EventsXML::write(const char *path) {
64 char file[PATH_MAX];
65
66 // Set full path
67 snprintf(file, PATH_MAX, "%s/events.xml", path);
68
69 char *buf = getXML();
70 if (util->writeToDisk(file, buf) < 0) {
71 logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify the path.", file);
72 handleException();
73 }
74
75 free(buf);
76}
diff --git a/tools/gator/daemon/EventsXML.h b/tools/gator/daemon/EventsXML.h
new file mode 100644
index 00000000000..ff7a02fd3c7
--- /dev/null
+++ b/tools/gator/daemon/EventsXML.h
@@ -0,0 +1,21 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef EVENTS_XML
10#define EVENTS_XML
11
12#include "mxml/mxml.h"
13
14class EventsXML {
15public:
16 mxml_node_t *getTree();
17 char *getXML();
18 void write(const char* path);
19};
20
21#endif // EVENTS_XML
diff --git a/tools/gator/daemon/ExternalSource.cpp b/tools/gator/daemon/ExternalSource.cpp
new file mode 100644
index 00000000000..b6ec301d0c0
--- /dev/null
+++ b/tools/gator/daemon/ExternalSource.cpp
@@ -0,0 +1,215 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "ExternalSource.h"
10
11#include <fcntl.h>
12#include <sys/prctl.h>
13#include <unistd.h>
14
15#include "Logging.h"
16#include "OlySocket.h"
17#include "SessionData.h"
18
19static const char MALI_VIDEO[] = "\0mali-video";
20static const char MALI_VIDEO_STARTUP[] = "\0mali-video-startup";
21static const char MALI_VIDEO_V1[] = "MALI_VIDEO 1\n";
22
23static bool setNonblock(const int fd) {
24 int flags;
25
26 flags = fcntl(fd, F_GETFL);
27 if (flags < 0) {
28 logg->logMessage("fcntl getfl failed");
29 return false;
30 }
31
32 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) {
33 logg->logMessage("fcntl setfl failed");
34 return false;
35 }
36
37 return true;
38}
39
40ExternalSource::ExternalSource(sem_t *senderSem) : mBuffer(0, FRAME_EXTERNAL, 128*1024, senderSem), mMonitor(), mMveStartupUds(MALI_VIDEO_STARTUP, sizeof(MALI_VIDEO_STARTUP)), mInterruptFd(-1), mMveUds(-1) {
41 sem_init(&mBufferSem, 0, 0);
42}
43
44ExternalSource::~ExternalSource() {
45}
46
47void ExternalSource::waitFor(const uint64_t currTime, const int bytes) {
48 while (mBuffer.bytesAvailable() <= bytes) {
49 mBuffer.check(currTime);
50 sem_wait(&mBufferSem);
51 }
52}
53
54void ExternalSource::configureConnection(const int fd, const char *const handshake, size_t size) {
55 if (!setNonblock(fd)) {
56 logg->logError(__FILE__, __LINE__, "Unable to set nonblock on fh");
57 handleException();
58 }
59
60 if (!mMonitor.add(fd)) {
61 logg->logError(__FILE__, __LINE__, "Unable to add fh to monitor");
62 handleException();
63 }
64
65 // Write the handshake to the circular buffer
66 waitFor(1, Buffer::MAXSIZE_PACK32 + 4 + size - 1);
67 mBuffer.packInt(fd);
68 mBuffer.writeLEInt((unsigned char *)mBuffer.getWritePos(), size - 1);
69 mBuffer.advanceWrite(4);
70 mBuffer.writeBytes(handshake, size - 1);
71}
72
73bool ExternalSource::connectMve() {
74 if (!gSessionData->maliVideo.countersEnabled()) {
75 return true;
76 }
77
78 mMveUds = OlySocket::connect(MALI_VIDEO, sizeof(MALI_VIDEO));
79 if (mMveUds < 0) {
80 return false;
81 }
82
83 if (!gSessionData->maliVideo.start(mMveUds)) {
84 return false;
85 }
86
87 configureConnection(mMveUds, MALI_VIDEO_V1, sizeof(MALI_VIDEO_V1));
88
89 return true;
90}
91
92bool ExternalSource::prepare() {
93 if (!mMonitor.init() || !setNonblock(mMveStartupUds.getFd()) || !mMonitor.add(mMveStartupUds.getFd())) {
94 return false;
95 }
96
97 connectMve();
98
99 return true;
100}
101
102void ExternalSource::run() {
103 int pipefd[2];
104
105 prctl(PR_SET_NAME, (unsigned long)&"gatord-external", 0, 0, 0);
106
107 if (pipe(pipefd) != 0) {
108 logg->logError(__FILE__, __LINE__, "pipe failed");
109 handleException();
110 }
111 mInterruptFd = pipefd[1];
112
113 if (!mMonitor.add(pipefd[0])) {
114 logg->logError(__FILE__, __LINE__, "Monitor::add failed");
115 handleException();
116 }
117
118 while (gSessionData->mSessionIsActive) {
119 struct epoll_event events[16];
120 // Clear any pending sem posts
121 while (sem_trywait(&mBufferSem) == 0);
122 int ready = mMonitor.wait(events, ARRAY_LENGTH(events), -1);
123 if (ready < 0) {
124 logg->logError(__FILE__, __LINE__, "Monitor::wait failed");
125 handleException();
126 }
127
128 const uint64_t currTime = getTime();
129
130 for (int i = 0; i < ready; ++i) {
131 const int fd = events[i].data.fd;
132 if (fd == mMveStartupUds.getFd()) {
133 // Mali Video Engine says it's alive
134 int client = mMveStartupUds.acceptConnection();
135 // Don't read from this connection, establish a new connection to Mali-V500
136 close(client);
137 if (!connectMve()) {
138 logg->logError(__FILE__, __LINE__, "Unable to configure incoming Mali video connection");
139 handleException();
140 }
141 } else if (fd == pipefd[0]) {
142 // Means interrupt has been called and mSessionIsActive should be reread
143 } else {
144 while (true) {
145 waitFor(currTime, Buffer::MAXSIZE_PACK32 + 4);
146
147 mBuffer.packInt(fd);
148 char *const bytesPos = mBuffer.getWritePos();
149 mBuffer.advanceWrite(4);
150 const int contiguous = mBuffer.contiguousSpaceAvailable();
151 const int bytes = read(fd, mBuffer.getWritePos(), contiguous);
152 if (bytes < 0) {
153 if (errno == EAGAIN) {
154 // Nothing left to read, and Buffer convention dictates that writePos can't go backwards
155 mBuffer.writeLEInt((unsigned char *)bytesPos, 0);
156 break;
157 }
158 // Something else failed, close the socket
159 mBuffer.writeLEInt((unsigned char *)bytesPos, -1);
160 close(fd);
161 break;
162 } else if (bytes == 0) {
163 // The other side is closed
164 mBuffer.writeLEInt((unsigned char *)bytesPos, -1);
165 close(fd);
166 break;
167 }
168
169 mBuffer.writeLEInt((unsigned char *)bytesPos, bytes);
170 mBuffer.advanceWrite(bytes);
171
172 // Short reads also mean nothing is left to read
173 if (bytes < contiguous) {
174 break;
175 }
176 }
177 }
178 }
179
180 // Only call mBufferCheck once per iteration
181 mBuffer.check(currTime);
182 }
183
184 mBuffer.setDone();
185
186 mInterruptFd = -1;
187 close(pipefd[0]);
188 close(pipefd[1]);
189}
190
191void ExternalSource::interrupt() {
192 if (mInterruptFd >= 0) {
193 int8_t c = 0;
194 // Write to the pipe to wake the monitor which will cause mSessionIsActive to be reread
195 if (::write(mInterruptFd, &c, sizeof(c)) != sizeof(c)) {
196 logg->logError(__FILE__, __LINE__, "write failed");
197 handleException();
198 }
199 }
200}
201
202bool ExternalSource::isDone() {
203 return mBuffer.isDone();
204}
205
206void ExternalSource::write(Sender *sender) {
207 // Don't send external data until the summary packet is sent so that monotonic delta is available
208 if (!gSessionData->mSentSummary) {
209 return;
210 }
211 if (!mBuffer.isDone()) {
212 mBuffer.write(sender);
213 sem_post(&mBufferSem);
214 }
215}
diff --git a/tools/gator/daemon/ExternalSource.h b/tools/gator/daemon/ExternalSource.h
new file mode 100644
index 00000000000..2e7ed27df25
--- /dev/null
+++ b/tools/gator/daemon/ExternalSource.h
@@ -0,0 +1,49 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef EXTERNALSOURCE_H
10#define EXTERNALSOURCE_H
11
12#include <semaphore.h>
13
14#include "Buffer.h"
15#include "Monitor.h"
16#include "OlySocket.h"
17#include "Source.h"
18
19// Unix domain socket counters from external sources like graphics drivers
20class ExternalSource : public Source {
21public:
22 ExternalSource(sem_t *senderSem);
23 ~ExternalSource();
24
25 bool prepare();
26 void run();
27 void interrupt();
28
29 bool isDone();
30 void write(Sender *sender);
31
32private:
33 void waitFor(const uint64_t currTime, const int bytes);
34 void configureConnection(const int fd, const char *const handshake, size_t size);
35 bool connectMve();
36
37 sem_t mBufferSem;
38 Buffer mBuffer;
39 Monitor mMonitor;
40 OlyServerSocket mMveStartupUds;
41 int mInterruptFd;
42 int mMveUds;
43
44 // Intentionally unimplemented
45 ExternalSource(const ExternalSource &);
46 ExternalSource &operator=(const ExternalSource &);
47};
48
49#endif // EXTERNALSOURCE_H
diff --git a/tools/gator/daemon/FSDriver.cpp b/tools/gator/daemon/FSDriver.cpp
new file mode 100644
index 00000000000..40c8df1af22
--- /dev/null
+++ b/tools/gator/daemon/FSDriver.cpp
@@ -0,0 +1,212 @@
1/**
2 * Copyright (C) ARM Limited 2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "FSDriver.h"
10
11#include <fcntl.h>
12#include <regex.h>
13#include <sys/stat.h>
14#include <sys/types.h>
15#include <unistd.h>
16
17#include "Buffer.h"
18#include "Counter.h"
19#include "DriverSource.h"
20#include "Logging.h"
21#include "SessionData.h"
22
23class FSCounter {
24public:
25 FSCounter(FSCounter *next, char *name, const char *regex);
26 ~FSCounter();
27
28 FSCounter *getNext() const { return next; }
29 int getKey() const { return key; }
30 bool isEnabled() const { return enabled; }
31 void setEnabled(const bool enabled) { this->enabled = enabled; }
32 const char *getName() const { return name; }
33 int64_t read();
34
35private:
36 FSCounter *const next;
37 regex_t reg;
38 char *name;
39 const int key;
40 int enabled : 1,
41 useRegex : 1;
42
43 // Intentionally unimplemented
44 FSCounter(const FSCounter &);
45 FSCounter &operator=(const FSCounter &);
46};
47
48FSCounter::FSCounter(FSCounter *next, char *name, const char *regex) : next(next), name(name), key(getEventKey()), enabled(false), useRegex(regex != NULL) {
49 if (useRegex) {
50 int result = regcomp(&reg, regex, REG_EXTENDED);
51 if (result != 0) {
52 char buf[128];
53 regerror(result, &reg, buf, sizeof(buf));
54 logg->logError(__FILE__, __LINE__, "Invalid regex '%s': %s", regex, buf);
55 handleException();
56 }
57 }
58}
59
60FSCounter::~FSCounter() {
61 free(name);
62 if (useRegex) {
63 regfree(&reg);
64 }
65}
66
67int64_t FSCounter::read() {
68 int64_t value;
69 if (useRegex) {
70 char buf[4096];
71 size_t pos = 0;
72 const int fd = open(name, O_RDONLY);
73 if (fd < 0) {
74 goto fail;
75 }
76 while (pos < sizeof(buf) - 1) {
77 const ssize_t bytes = ::read(fd, buf + pos, sizeof(buf) - pos - 1);
78 if (bytes < 0) {
79 goto fail;
80 } else if (bytes == 0) {
81 break;
82 }
83 pos += bytes;
84 }
85 close(fd);
86 buf[pos] = '\0';
87
88 regmatch_t match[2];
89 int result = regexec(&reg, buf, 2, match, 0);
90 if (result != 0) {
91 regerror(result, &reg, buf, sizeof(buf));
92 logg->logError(__FILE__, __LINE__, "Parsing %s failed: %s", name, buf);
93 handleException();
94 }
95
96 if (match[1].rm_so < 0) {
97 logg->logError(__FILE__, __LINE__, "Parsing %s failed", name);
98 handleException();
99 }
100 char *endptr;
101 errno = 0;
102 value = strtoll(buf + match[1].rm_so, &endptr, 0);
103 if (errno != 0) {
104 logg->logError(__FILE__, __LINE__, "Parsing %s failed: %s", name, strerror(errno));
105 handleException();
106 }
107 } else {
108 if (DriverSource::readInt64Driver(name, &value) != 0) {
109 goto fail;
110 }
111 }
112 return value;
113
114 fail:
115 logg->logError(__FILE__, __LINE__, "Unable to read %s", name);
116 handleException();
117}
118
119FSDriver::FSDriver() : counters(NULL) {
120}
121
122FSDriver::~FSDriver() {
123 while (counters != NULL) {
124 FSCounter * counter = counters;
125 counters = counter->getNext();
126 delete counter;
127 }
128}
129
130void FSDriver::setup(mxml_node_t *const xml) {
131 // fs driver does not currently work with perf
132 if (gSessionData->perf.isSetup()) {
133 return;
134 }
135
136 mxml_node_t *node = xml;
137 while (true) {
138 node = mxmlFindElement(node, xml, "event", NULL, NULL, MXML_DESCEND);
139 if (node == NULL) {
140 break;
141 }
142 const char *counter = mxmlElementGetAttr(node, "counter");
143 if ((counter != NULL) && (counter[0] == '/')) {
144 const char *regex = mxmlElementGetAttr(node, "regex");
145 counters = new FSCounter(counters, strdup(counter), regex);
146 }
147 }
148}
149
150FSCounter *FSDriver::findCounter(const Counter &counter) const {
151 for (FSCounter * fsCounter = counters; fsCounter != NULL; fsCounter = fsCounter->getNext()) {
152 if (strcmp(fsCounter->getName(), counter.getType()) == 0) {
153 return fsCounter;
154 }
155 }
156
157 return NULL;
158}
159
160bool FSDriver::claimCounter(const Counter &counter) const {
161 return findCounter(counter) != NULL;
162}
163
164bool FSDriver::countersEnabled() const {
165 for (FSCounter *counter = counters; counter != NULL; counter = counter->getNext()) {
166 if (counter->isEnabled()) {
167 return true;
168 }
169 }
170 return false;
171}
172
173void FSDriver::resetCounters() {
174 for (FSCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
175 counter->setEnabled(false);
176 }
177}
178
179void FSDriver::setupCounter(Counter &counter) {
180 FSCounter *const fsCounter = findCounter(counter);
181 if (fsCounter == NULL) {
182 counter.setEnabled(false);
183 return;
184 }
185 fsCounter->setEnabled(true);
186 counter.setKey(fsCounter->getKey());
187}
188
189int FSDriver::writeCounters(mxml_node_t *root) const {
190 int count = 0;
191 for (FSCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
192 if (access(counter->getName(), R_OK) == 0) {
193 mxml_node_t *node = mxmlNewElement(root, "counter");
194 mxmlElementSetAttr(node, "name", counter->getName());
195 ++count;
196 }
197 }
198
199 return count;
200}
201
202void FSDriver::start() {
203}
204
205void FSDriver::read(Buffer * const buffer) {
206 for (FSCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
207 if (!counter->isEnabled()) {
208 continue;
209 }
210 buffer->event(counter->getKey(), counter->read());
211 }
212}
diff --git a/tools/gator/daemon/FSDriver.h b/tools/gator/daemon/FSDriver.h
new file mode 100644
index 00000000000..ef395536233
--- /dev/null
+++ b/tools/gator/daemon/FSDriver.h
@@ -0,0 +1,44 @@
1/**
2 * Copyright (C) ARM Limited 2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef FSDRIVER_H
10#define FSDRIVER_H
11
12#include "Driver.h"
13
14class Buffer;
15class FSCounter;
16
17class FSDriver : public Driver {
18public:
19 FSDriver();
20 ~FSDriver();
21
22 void setup(mxml_node_t *const xml);
23
24 bool claimCounter(const Counter &counter) const;
25 bool countersEnabled() const;
26 void resetCounters();
27 void setupCounter(Counter &counter);
28
29 int writeCounters(mxml_node_t *root) const;
30
31 void start();
32 void read(Buffer * buffer);
33
34private:
35 FSCounter *findCounter(const Counter &counter) const;
36
37 FSCounter *counters;
38
39 // Intentionally unimplemented
40 FSDriver(const FSDriver &);
41 FSDriver &operator=(const FSDriver &);
42};
43
44#endif // FSDRIVER_H
diff --git a/tools/gator/daemon/Fifo.cpp b/tools/gator/daemon/Fifo.cpp
new file mode 100644
index 00000000000..f672e92a680
--- /dev/null
+++ b/tools/gator/daemon/Fifo.cpp
@@ -0,0 +1,130 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "Fifo.h"
10
11#include <stdlib.h>
12#ifdef WIN32
13#define valloc malloc
14#endif
15
16#include "Logging.h"
17
18// bufferSize is the amount of data to be filled
19// singleBufferSize is the maximum size that may be filled during a single write
20// (bufferSize + singleBufferSize) will be allocated
21Fifo::Fifo(int singleBufferSize, int bufferSize, sem_t* readerSem) {
22 mWrite = mRead = mReadCommit = mRaggedEnd = 0;
23 mWrapThreshold = bufferSize;
24 mSingleBufferSize = singleBufferSize;
25 mReaderSem = readerSem;
26 mBuffer = (char*)valloc(bufferSize + singleBufferSize);
27 mEnd = false;
28
29 if (mBuffer == NULL) {
30 logg->logError(__FILE__, __LINE__, "failed to allocate %d bytes", bufferSize + singleBufferSize);
31 handleException();
32 }
33
34 if (sem_init(&mWaitForSpaceSem, 0, 0)) {
35 logg->logError(__FILE__, __LINE__, "sem_init() failed");
36 handleException();
37 }
38}
39
40Fifo::~Fifo() {
41 free(mBuffer);
42 sem_destroy(&mWaitForSpaceSem);
43}
44
45int Fifo::numBytesFilled() const {
46 return mWrite - mRead + mRaggedEnd;
47}
48
49char* Fifo::start() const {
50 return mBuffer;
51}
52
53bool Fifo::isEmpty() const {
54 return mRead == mWrite && mRaggedEnd == 0;
55}
56
57bool Fifo::isFull() const {
58 return willFill(0);
59}
60
61// Determines if the buffer will fill assuming 'additional' bytes will be added to the buffer
62// 'full' means there is less than singleBufferSize bytes available contiguously; it does not mean there are zero bytes available
63bool Fifo::willFill(int additional) const {
64 if (mWrite > mRead) {
65 if (numBytesFilled() + additional < mWrapThreshold) {
66 return false;
67 }
68 } else {
69 if (numBytesFilled() + additional < mWrapThreshold - mSingleBufferSize) {
70 return false;
71 }
72 }
73 return true;
74}
75
76// This function will stall until contiguous singleBufferSize bytes are available
77char* Fifo::write(int length) {
78 if (length <= 0) {
79 length = 0;
80 mEnd = true;
81 }
82
83 // update the write pointer
84 mWrite += length;
85
86 // handle the wrap-around
87 if (mWrite >= mWrapThreshold) {
88 mRaggedEnd = mWrite;
89 mWrite = 0;
90 }
91
92 // send a notification that data is ready
93 sem_post(mReaderSem);
94
95 // wait for space
96 while (isFull()) {
97 sem_wait(&mWaitForSpaceSem);
98 }
99
100 return &mBuffer[mWrite];
101}
102
103void Fifo::release() {
104 // update the read pointer now that the data has been handled
105 mRead = mReadCommit;
106
107 // handle the wrap-around
108 if (mRead >= mWrapThreshold) {
109 mRaggedEnd = mRead = mReadCommit = 0;
110 }
111
112 // send a notification that data is free (space is available)
113 sem_post(&mWaitForSpaceSem);
114}
115
116// This function will return null if no data is available
117char* Fifo::read(int *const length) {
118 // wait for data
119 if (isEmpty() && !mEnd) {
120 return NULL;
121 }
122
123 // obtain the length
124 do {
125 mReadCommit = mRaggedEnd ? mRaggedEnd : mWrite;
126 *length = mReadCommit - mRead;
127 } while (*length < 0); // plugs race condition without using semaphores
128
129 return &mBuffer[mRead];
130}
diff --git a/tools/gator/daemon/Fifo.h b/tools/gator/daemon/Fifo.h
new file mode 100644
index 00000000000..bdda3f549b5
--- /dev/null
+++ b/tools/gator/daemon/Fifo.h
@@ -0,0 +1,48 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef __FIFO_H__
10#define __FIFO_H__
11
12#ifdef WIN32
13#include <windows.h>
14#define sem_t HANDLE
15#define sem_init(sem, pshared, value) ((*(sem) = CreateSemaphore(NULL, value, LONG_MAX, NULL)) == NULL)
16#define sem_wait(sem) WaitForSingleObject(*(sem), INFINITE)
17#define sem_post(sem) ReleaseSemaphore(*(sem), 1, NULL)
18#define sem_destroy(sem) CloseHandle(*(sem))
19#else
20#include <semaphore.h>
21#endif
22
23class Fifo {
24public:
25 Fifo(int singleBufferSize, int totalBufferSize, sem_t* readerSem);
26 ~Fifo();
27 int numBytesFilled() const;
28 bool isEmpty() const;
29 bool isFull() const;
30 bool willFill(int additional) const;
31 char* start() const;
32 char* write(int length);
33 void release();
34 char* read(int *const length);
35
36private:
37 int mSingleBufferSize, mWrite, mRead, mReadCommit, mRaggedEnd, mWrapThreshold;
38 sem_t mWaitForSpaceSem;
39 sem_t* mReaderSem;
40 char* mBuffer;
41 bool mEnd;
42
43 // Intentionally unimplemented
44 Fifo(const Fifo &);
45 Fifo &operator=(const Fifo &);
46};
47
48#endif //__FIFO_H__
diff --git a/tools/gator/daemon/Hwmon.cpp b/tools/gator/daemon/Hwmon.cpp
new file mode 100644
index 00000000000..e44424743ef
--- /dev/null
+++ b/tools/gator/daemon/Hwmon.cpp
@@ -0,0 +1,352 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "Hwmon.h"
10
11#include "libsensors/sensors.h"
12
13#include "Buffer.h"
14#include "Counter.h"
15#include "Logging.h"
16#include "SessionData.h"
17
18class HwmonCounter {
19public:
20 HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, const sensors_feature *feature);
21 ~HwmonCounter();
22
23 HwmonCounter *getNext() const { return next; }
24 int getKey() const { return key; }
25 bool isEnabled() const { return enabled; }
26 const char *getName() const { return name; }
27 const char *getLabel() const { return label; }
28 const char *getTitle() const { return title; }
29 bool isDuplicate() const { return duplicate; }
30 const char *getDisplay() const { return display; }
31 const char *getCounterClass() const { return counter_class; }
32 const char *getUnit() const { return unit; }
33 int getModifier() const { return modifier; }
34
35 void setEnabled(const bool enabled) {
36 this->enabled = enabled;
37 // canRead will clear enabled if the counter is not readable
38 canRead();
39 }
40
41 double read();
42 bool canRead();
43
44private:
45 void init(const sensors_chip_name *chip, const sensors_feature *feature);
46
47 HwmonCounter *const next;
48 const int key;
49 int polled : 1,
50 readable : 1,
51 enabled : 1,
52 monotonic: 1,
53 duplicate : 1;
54
55 const sensors_chip_name *chip;
56 const sensors_feature *feature;
57
58 char *name;
59 char *label;
60 const char *title;
61 const char *display;
62 const char *counter_class;
63 const char *unit;
64 int modifier;
65 double previous_value;
66
67 sensors_subfeature_type input;
68
69 // Intentionally unimplemented
70 HwmonCounter(const HwmonCounter &);
71 HwmonCounter &operator=(const HwmonCounter &);
72};
73
74HwmonCounter::HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, const sensors_feature *feature) : next(next), key(getEventKey()), polled(false), readable(false), enabled(false), duplicate(false), chip(chip), feature(feature) {
75
76 int len = sensors_snprintf_chip_name(NULL, 0, chip) + 1;
77 char *chip_name = new char[len];
78 sensors_snprintf_chip_name(chip_name, len, chip);
79
80 len = snprintf(NULL, 0, "hwmon_%s_%d", chip_name, feature->number) + 1;
81 name = new char[len];
82 snprintf(name, len, "hwmon_%s_%d", chip_name, feature->number);
83
84 delete [] chip_name;
85
86 label = sensors_get_label(chip, feature);
87
88 switch (feature->type) {
89 case SENSORS_FEATURE_IN:
90 title = "Voltage";
91 input = SENSORS_SUBFEATURE_IN_INPUT;
92 display = "maximum";
93 counter_class = "absolute";
94 unit = "V";
95 modifier = 1000;
96 monotonic = false;
97 break;
98 case SENSORS_FEATURE_FAN:
99 title = "Fan";
100 input = SENSORS_SUBFEATURE_FAN_INPUT;
101 display = "average";
102 counter_class = "absolute";
103 unit = "RPM";
104 modifier = 1;
105 monotonic = false;
106 break;
107 case SENSORS_FEATURE_TEMP:
108 title = "Temperature";
109 input = SENSORS_SUBFEATURE_TEMP_INPUT;
110 display = "maximum";
111 counter_class = "absolute";
112 unit = "°C";
113 modifier = 1000;
114 monotonic = false;
115 break;
116 case SENSORS_FEATURE_POWER:
117 title = "Power";
118 input = SENSORS_SUBFEATURE_POWER_INPUT;
119 display = "maximum";
120 counter_class = "absolute";
121 unit = "W";
122 modifier = 1000000;
123 monotonic = false;
124 break;
125 case SENSORS_FEATURE_ENERGY:
126 title = "Energy";
127 input = SENSORS_SUBFEATURE_ENERGY_INPUT;
128 display = "accumulate";
129 counter_class = "delta";
130 unit = "J";
131 modifier = 1000000;
132 monotonic = true;
133 break;
134 case SENSORS_FEATURE_CURR:
135 title = "Current";
136 input = SENSORS_SUBFEATURE_CURR_INPUT;
137 display = "maximum";
138 counter_class = "absolute";
139 unit = "A";
140 modifier = 1000;
141 monotonic = false;
142 break;
143 case SENSORS_FEATURE_HUMIDITY:
144 title = "Humidity";
145 input = SENSORS_SUBFEATURE_HUMIDITY_INPUT;
146 display = "average";
147 counter_class = "absolute";
148 unit = "%";
149 modifier = 1000;
150 monotonic = false;
151 break;
152 default:
153 logg->logError(__FILE__, __LINE__, "Unsupported hwmon feature %i", feature->type);
154 handleException();
155 }
156
157 for (HwmonCounter * counter = next; counter != NULL; counter = counter->getNext()) {
158 if (strcmp(label, counter->getLabel()) == 0 && strcmp(title, counter->getTitle()) == 0) {
159 duplicate = true;
160 counter->duplicate = true;
161 break;
162 }
163 }
164}
165
166HwmonCounter::~HwmonCounter() {
167 free((void *)label);
168 delete [] name;
169}
170
171double HwmonCounter::read() {
172 double value;
173 double result;
174 const sensors_subfeature *subfeature;
175
176 // Keep in sync with canRead
177 subfeature = sensors_get_subfeature(chip, feature, input);
178 if (!subfeature) {
179 logg->logError(__FILE__, __LINE__, "No input value for hwmon sensor %s", label);
180 handleException();
181 }
182
183 if (sensors_get_value(chip, subfeature->number, &value) != 0) {
184 logg->logError(__FILE__, __LINE__, "Can't get input value for hwmon sensor %s", label);
185 handleException();
186 }
187
188 result = (monotonic ? value - previous_value : value);
189 previous_value = value;
190
191 return result;
192}
193
194bool HwmonCounter::canRead() {
195 if (!polled) {
196 double value;
197 const sensors_subfeature *subfeature;
198 bool result = true;
199
200 subfeature = sensors_get_subfeature(chip, feature, input);
201 if (!subfeature) {
202 result = false;
203 } else {
204 result = sensors_get_value(chip, subfeature->number, &value) == 0;
205 }
206
207 polled = true;
208 readable = result;
209 }
210
211 enabled &= readable;
212
213 return readable;
214}
215
216Hwmon::Hwmon() : counters(NULL) {
217}
218
219Hwmon::~Hwmon() {
220 while (counters != NULL) {
221 HwmonCounter * counter = counters;
222 counters = counter->getNext();
223 delete counter;
224 }
225 sensors_cleanup();
226}
227
228void Hwmon::setup() {
229 // hwmon does not currently work with perf
230 if (gSessionData->perf.isSetup()) {
231 return;
232 }
233
234 int err = sensors_init(NULL);
235 if (err) {
236 logg->logMessage("Failed to initialize libsensors! (%d)", err);
237 return;
238 }
239 sensors_sysfs_no_scaling = 1;
240
241 int chip_nr = 0;
242 const sensors_chip_name *chip;
243 while ((chip = sensors_get_detected_chips(NULL, &chip_nr))) {
244 int feature_nr = 0;
245 const sensors_feature *feature;
246 while ((feature = sensors_get_features(chip, &feature_nr))) {
247 counters = new HwmonCounter(counters, chip, feature);
248 }
249 }
250}
251
252HwmonCounter *Hwmon::findCounter(const Counter &counter) const {
253 for (HwmonCounter * hwmonCounter = counters; hwmonCounter != NULL; hwmonCounter = hwmonCounter->getNext()) {
254 if (hwmonCounter->canRead() && strcmp(hwmonCounter->getName(), counter.getType()) == 0) {
255 return hwmonCounter;
256 }
257 }
258
259 return NULL;
260}
261
262bool Hwmon::claimCounter(const Counter &counter) const {
263 return findCounter(counter) != NULL;
264}
265
266bool Hwmon::countersEnabled() const {
267 for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
268 if (counter->isEnabled()) {
269 return true;
270 }
271 }
272 return false;
273}
274
275void Hwmon::resetCounters() {
276 for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
277 counter->setEnabled(false);
278 }
279}
280
281void Hwmon::setupCounter(Counter &counter) {
282 HwmonCounter *const hwmonCounter = findCounter(counter);
283 if (hwmonCounter == NULL) {
284 counter.setEnabled(false);
285 return;
286 }
287 hwmonCounter->setEnabled(true);
288 counter.setKey(hwmonCounter->getKey());
289}
290
291int Hwmon::writeCounters(mxml_node_t *root) const {
292 int count = 0;
293 for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
294 if (!counter->canRead()) {
295 continue;
296 }
297 mxml_node_t *node = mxmlNewElement(root, "counter");
298 mxmlElementSetAttr(node, "name", counter->getName());
299 ++count;
300 }
301
302 return count;
303}
304
305void Hwmon::writeEvents(mxml_node_t *root) const {
306 root = mxmlNewElement(root, "category");
307 mxmlElementSetAttr(root, "name", "hwmon");
308
309 char buf[1024];
310 for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
311 if (!counter->canRead()) {
312 continue;
313 }
314 mxml_node_t *node = mxmlNewElement(root, "event");
315 mxmlElementSetAttr(node, "counter", counter->getName());
316 mxmlElementSetAttr(node, "title", counter->getTitle());
317 if (counter->isDuplicate()) {
318 mxmlElementSetAttrf(node, "name", "%s (0x%x)", counter->getLabel(), counter->getKey());
319 } else {
320 mxmlElementSetAttr(node, "name", counter->getLabel());
321 }
322 mxmlElementSetAttr(node, "display", counter->getDisplay());
323 mxmlElementSetAttr(node, "class", counter->getCounterClass());
324 mxmlElementSetAttr(node, "units", counter->getUnit());
325 if (counter->getModifier() != 1) {
326 mxmlElementSetAttrf(node, "modifier", "%d", counter->getModifier());
327 }
328 if (strcmp(counter->getDisplay(), "average") == 0 || strcmp(counter->getDisplay(), "maximum") == 0) {
329 mxmlElementSetAttr(node, "average_selection", "yes");
330 }
331 snprintf(buf, sizeof(buf), "libsensors %s sensor %s (%s)", counter->getTitle(), counter->getLabel(), counter->getName());
332 mxmlElementSetAttr(node, "description", buf);
333 }
334}
335
336void Hwmon::start() {
337 for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
338 if (!counter->isEnabled()) {
339 continue;
340 }
341 counter->read();
342 }
343}
344
345void Hwmon::read(Buffer * const buffer) {
346 for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
347 if (!counter->isEnabled()) {
348 continue;
349 }
350 buffer->event(counter->getKey(), counter->read());
351 }
352}
diff --git a/tools/gator/daemon/Hwmon.h b/tools/gator/daemon/Hwmon.h
new file mode 100644
index 00000000000..a22a3609f99
--- /dev/null
+++ b/tools/gator/daemon/Hwmon.h
@@ -0,0 +1,45 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef HWMON_H
10#define HWMON_H
11
12#include "Driver.h"
13
14class Buffer;
15class HwmonCounter;
16
17class Hwmon : public Driver {
18public:
19 Hwmon();
20 ~Hwmon();
21
22 void setup();
23
24 bool claimCounter(const Counter &counter) const;
25 bool countersEnabled() const;
26 void resetCounters();
27 void setupCounter(Counter &counter);
28
29 int writeCounters(mxml_node_t *root) const;
30 void writeEvents(mxml_node_t *root) const;
31
32 void start();
33 void read(Buffer * buffer);
34
35private:
36 HwmonCounter *findCounter(const Counter &counter) const;
37
38 HwmonCounter *counters;
39
40 // Intentionally unimplemented
41 Hwmon(const Hwmon &);
42 Hwmon &operator=(const Hwmon &);
43};
44
45#endif // HWMON_H
diff --git a/tools/gator/daemon/KMod.cpp b/tools/gator/daemon/KMod.cpp
new file mode 100644
index 00000000000..73e123d2f14
--- /dev/null
+++ b/tools/gator/daemon/KMod.cpp
@@ -0,0 +1,110 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "KMod.h"
10
11#include <sys/types.h>
12#include <dirent.h>
13#include <unistd.h>
14
15#include "ConfigurationXML.h"
16#include "Counter.h"
17#include "DriverSource.h"
18#include "Logging.h"
19
20// Claim all the counters in /dev/gator/events
21bool KMod::claimCounter(const Counter &counter) const {
22 char text[128];
23 snprintf(text, sizeof(text), "/dev/gator/events/%s", counter.getType());
24 return access(text, F_OK) == 0;
25}
26
27void KMod::resetCounters() {
28 char base[128];
29 char text[128];
30
31 // Initialize all perf counters in the driver, i.e. set enabled to zero
32 struct dirent *ent;
33 DIR* dir = opendir("/dev/gator/events");
34 if (dir) {
35 while ((ent = readdir(dir)) != NULL) {
36 // skip hidden files, current dir, and parent dir
37 if (ent->d_name[0] == '.')
38 continue;
39 snprintf(base, sizeof(base), "/dev/gator/events/%s", ent->d_name);
40 snprintf(text, sizeof(text), "%s/enabled", base);
41 DriverSource::writeDriver(text, 0);
42 snprintf(text, sizeof(text), "%s/count", base);
43 DriverSource::writeDriver(text, 0);
44 }
45 closedir(dir);
46 }
47}
48
49void KMod::setupCounter(Counter &counter) {
50 char base[128];
51 char text[128];
52 snprintf(base, sizeof(base), "/dev/gator/events/%s", counter.getType());
53
54 snprintf(text, sizeof(text), "%s/enabled", base);
55 int enabled = true;
56 if (DriverSource::writeReadDriver(text, &enabled) || !enabled) {
57 counter.setEnabled(false);
58 return;
59 }
60
61 int value = 0;
62 snprintf(text, sizeof(text), "%s/key", base);
63 DriverSource::readIntDriver(text, &value);
64 counter.setKey(value);
65
66 snprintf(text, sizeof(text), "%s/cores", base);
67 if (DriverSource::readIntDriver(text, &value) == 0) {
68 counter.setCores(value);
69 }
70
71 snprintf(text, sizeof(text), "%s/event", base);
72 DriverSource::writeDriver(text, counter.getEvent());
73 snprintf(text, sizeof(text), "%s/count", base);
74 if (access(text, F_OK) == 0) {
75 int count = counter.getCount();
76 if (DriverSource::writeReadDriver(text, &count) && counter.getCount() > 0) {
77 logg->logError(__FILE__, __LINE__, "Cannot enable EBS for %s:%i with a count of %d\n", counter.getType(), counter.getEvent(), counter.getCount());
78 handleException();
79 }
80 counter.setCount(count);
81 } else if (counter.getCount() > 0) {
82 ConfigurationXML::remove();
83 logg->logError(__FILE__, __LINE__, "Event Based Sampling is only supported with kernel versions 3.0.0 and higher with CONFIG_PERF_EVENTS=y, and CONFIG_HW_PERF_EVENTS=y. The invalid configuration.xml has been removed.\n");
84 handleException();
85 }
86}
87
88int KMod::writeCounters(mxml_node_t *root) const {
89 struct dirent *ent;
90 mxml_node_t *counter;
91
92 // counters.xml is simply a file listing of /dev/gator/events
93 DIR* dir = opendir("/dev/gator/events");
94 if (dir == NULL) {
95 return 0;
96 }
97
98 int count = 0;
99 while ((ent = readdir(dir)) != NULL) {
100 // skip hidden files, current dir, and parent dir
101 if (ent->d_name[0] == '.')
102 continue;
103 counter = mxmlNewElement(root, "counter");
104 mxmlElementSetAttr(counter, "name", ent->d_name);
105 ++count;
106 }
107 closedir(dir);
108
109 return count;
110}
diff --git a/tools/gator/daemon/KMod.h b/tools/gator/daemon/KMod.h
new file mode 100644
index 00000000000..fb7fc8a8f9c
--- /dev/null
+++ b/tools/gator/daemon/KMod.h
@@ -0,0 +1,27 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef KMOD_H
10#define KMOD_H
11
12#include "Driver.h"
13
14// Driver for the gator kernel module
15class KMod : public Driver {
16public:
17 KMod() {}
18 ~KMod() {}
19
20 bool claimCounter(const Counter &counter) const;
21 void resetCounters();
22 void setupCounter(Counter &counter);
23
24 int writeCounters(mxml_node_t *root) const;
25};
26
27#endif // KMOD_H
diff --git a/tools/gator/daemon/LocalCapture.cpp b/tools/gator/daemon/LocalCapture.cpp
new file mode 100644
index 00000000000..d2a4b799d7a
--- /dev/null
+++ b/tools/gator/daemon/LocalCapture.cpp
@@ -0,0 +1,131 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "LocalCapture.h"
10
11#include <sys/stat.h>
12#include <sys/types.h>
13#include <dirent.h>
14#include <string.h>
15#include <stdlib.h>
16#include <unistd.h>
17
18#include "SessionData.h"
19#include "Logging.h"
20#include "OlyUtility.h"
21#include "EventsXML.h"
22
23LocalCapture::LocalCapture() {}
24
25LocalCapture::~LocalCapture() {}
26
27void LocalCapture::createAPCDirectory(char* target_path) {
28 gSessionData->mAPCDir = createUniqueDirectory(target_path, ".apc");
29 if ((removeDirAndAllContents(gSessionData->mAPCDir) != 0 || mkdir(gSessionData->mAPCDir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0)) {
30 logg->logError(__FILE__, __LINE__, "Unable to create directory %s", gSessionData->mAPCDir);
31 handleException();
32 }
33}
34
35void LocalCapture::write(char* string) {
36 char file[PATH_MAX];
37
38 // Set full path
39 snprintf(file, PATH_MAX, "%s/session.xml", gSessionData->mAPCDir);
40
41 // Write the file
42 if (util->writeToDisk(file, string) < 0) {
43 logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify the path.", file);
44 handleException();
45 }
46
47 // Write events XML
48 EventsXML eventsXML;
49 eventsXML.write(gSessionData->mAPCDir);
50}
51
52char* LocalCapture::createUniqueDirectory(const char* initialPath, const char* ending) {
53 char* output;
54 char path[PATH_MAX];
55
56 // Ensure the path is an absolute path, i.e. starts with a slash
57 if (initialPath == 0 || strlen(initialPath) == 0) {
58 logg->logError(__FILE__, __LINE__, "Missing -o command line option required for a local capture.");
59 handleException();
60 } else if (initialPath[0] != '/') {
61 if (getcwd(path, PATH_MAX) == 0) {
62 logg->logMessage("Unable to retrieve the current working directory");
63 }
64 strncat(path, "/", PATH_MAX - strlen(path) - 1);
65 strncat(path, initialPath, PATH_MAX - strlen(path) - 1);
66 } else {
67 strncpy(path, initialPath, PATH_MAX);
68 path[PATH_MAX - 1] = 0; // strncpy does not guarantee a null-terminated string
69 }
70
71 // Add ending if it is not already there
72 if (strcmp(&path[strlen(path) - strlen(ending)], ending) != 0) {
73 strncat(path, ending, PATH_MAX - strlen(path) - 1);
74 }
75
76 output = strdup(path);
77
78 return output;
79}
80
81int LocalCapture::removeDirAndAllContents(char* path) {
82 int error = 0;
83 struct stat mFileInfo;
84 // Does the path exist?
85 if (stat(path, &mFileInfo) == 0) {
86 // Is it a directory?
87 if (mFileInfo.st_mode & S_IFDIR) {
88 DIR * dir = opendir(path);
89 dirent* entry = readdir(dir);
90 while (entry) {
91 if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
92 char* newpath = (char*)malloc(strlen(path) + strlen(entry->d_name) + 2);
93 sprintf(newpath, "%s/%s", path, entry->d_name);
94 error = removeDirAndAllContents(newpath);
95 free(newpath);
96 if (error) {
97 break;
98 }
99 }
100 entry = readdir(dir);
101 }
102 closedir(dir);
103 if (error == 0) {
104 error = rmdir(path);
105 }
106 } else {
107 error = remove(path);
108 }
109 }
110 return error;
111}
112
113void LocalCapture::copyImages(ImageLinkList* ptr) {
114 char dstfilename[PATH_MAX];
115
116 while (ptr) {
117 strncpy(dstfilename, gSessionData->mAPCDir, PATH_MAX);
118 dstfilename[PATH_MAX - 1] = 0; // strncpy does not guarantee a null-terminated string
119 if (gSessionData->mAPCDir[strlen(gSessionData->mAPCDir) - 1] != '/') {
120 strncat(dstfilename, "/", PATH_MAX - strlen(dstfilename) - 1);
121 }
122 strncat(dstfilename, util->getFilePart(ptr->path), PATH_MAX - strlen(dstfilename) - 1);
123 if (util->copyFile(ptr->path, dstfilename)) {
124 logg->logMessage("copied file %s to %s", ptr->path, dstfilename);
125 } else {
126 logg->logMessage("copy of file %s to %s failed", ptr->path, dstfilename);
127 }
128
129 ptr = ptr->next;
130 }
131}
diff --git a/tools/gator/daemon/LocalCapture.h b/tools/gator/daemon/LocalCapture.h
new file mode 100644
index 00000000000..b1e7219795c
--- /dev/null
+++ b/tools/gator/daemon/LocalCapture.h
@@ -0,0 +1,26 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef __LOCAL_CAPTURE_H__
10#define __LOCAL_CAPTURE_H__
11
12struct ImageLinkList;
13
14class LocalCapture {
15public:
16 LocalCapture();
17 ~LocalCapture();
18 void write(char* string);
19 void copyImages(ImageLinkList* ptr);
20 void createAPCDirectory(char* target_path);
21private:
22 char* createUniqueDirectory(const char* path, const char* ending);
23 int removeDirAndAllContents(char* path);
24};
25
26#endif //__LOCAL_CAPTURE_H__
diff --git a/tools/gator/daemon/Logging.cpp b/tools/gator/daemon/Logging.cpp
new file mode 100644
index 00000000000..b8d3178950d
--- /dev/null
+++ b/tools/gator/daemon/Logging.cpp
@@ -0,0 +1,78 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "Logging.h"
10
11#include <stdio.h>
12#include <stdlib.h>
13#include <stdarg.h>
14#include <string.h>
15
16#ifdef WIN32
17#define MUTEX_INIT() mLoggingMutex = CreateMutex(NULL, false, NULL);
18#define MUTEX_LOCK() WaitForSingleObject(mLoggingMutex, 0xFFFFFFFF);
19#define MUTEX_UNLOCK() ReleaseMutex(mLoggingMutex);
20#define snprintf _snprintf
21#else
22#include <pthread.h>
23#define MUTEX_INIT() pthread_mutex_init(&mLoggingMutex, NULL)
24#define MUTEX_LOCK() pthread_mutex_lock(&mLoggingMutex)
25#define MUTEX_UNLOCK() pthread_mutex_unlock(&mLoggingMutex)
26#endif
27
28// Global thread-safe logging
29Logging* logg = NULL;
30
31Logging::Logging(bool debug) {
32 mDebug = debug;
33 MUTEX_INIT();
34
35 strcpy(mErrBuf, "Unknown Error");
36 strcpy(mLogBuf, "Unknown Message");
37}
38
39Logging::~Logging() {
40}
41
42void Logging::logError(const char* file, int line, const char* fmt, ...) {
43 va_list args;
44
45 MUTEX_LOCK();
46 if (mDebug) {
47 snprintf(mErrBuf, sizeof(mErrBuf), "ERROR[%s:%d]: ", file, line);
48 } else {
49 mErrBuf[0] = 0;
50 }
51
52 va_start(args, fmt);
53 vsnprintf(mErrBuf + strlen(mErrBuf), sizeof(mErrBuf) - 2 - strlen(mErrBuf), fmt, args); // subtract 2 for \n and \0
54 va_end(args);
55
56 if (strlen(mErrBuf) > 0) {
57 strcat(mErrBuf, "\n");
58 }
59 MUTEX_UNLOCK();
60}
61
62void Logging::logMessage(const char* fmt, ...) {
63 if (mDebug) {
64 va_list args;
65
66 MUTEX_LOCK();
67 strcpy(mLogBuf, "INFO: ");
68
69 va_start(args, fmt);
70 vsnprintf(mLogBuf + strlen(mLogBuf), sizeof(mLogBuf) - 2 - strlen(mLogBuf), fmt, args); // subtract 2 for \n and \0
71 va_end(args);
72 strcat(mLogBuf, "\n");
73
74 fprintf(stdout, "%s", mLogBuf);
75 fflush(stdout);
76 MUTEX_UNLOCK();
77 }
78}
diff --git a/tools/gator/daemon/Logging.h b/tools/gator/daemon/Logging.h
new file mode 100644
index 00000000000..4934bb07975
--- /dev/null
+++ b/tools/gator/daemon/Logging.h
@@ -0,0 +1,36 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef __LOGGING_H__
10#define __LOGGING_H__
11
12#include <pthread.h>
13
14#define DRIVER_ERROR "\n Driver issue:\n >> gator.ko must be built against the current kernel version & configuration\n >> gator.ko should be co-located with gatord in the same directory\n >> OR insmod gator.ko prior to launching gatord"
15
16class Logging {
17public:
18 Logging(bool debug);
19 ~Logging();
20 void logError(const char* file, int line, const char* fmt, ...);
21 void logMessage(const char* fmt, ...);
22 char* getLastError() {return mErrBuf;}
23 char* getLastMessage() {return mLogBuf;}
24
25private:
26 char mErrBuf[4096]; // Arbitrarily large buffer to hold a string
27 char mLogBuf[4096]; // Arbitrarily large buffer to hold a string
28 bool mDebug;
29 pthread_mutex_t mLoggingMutex;
30};
31
32extern Logging* logg;
33
34extern void handleException() __attribute__ ((noreturn));
35
36#endif //__LOGGING_H__
diff --git a/tools/gator/daemon/Makefile b/tools/gator/daemon/Makefile
new file mode 100644
index 00000000000..2ed49fdb688
--- /dev/null
+++ b/tools/gator/daemon/Makefile
@@ -0,0 +1,25 @@
1#
2# Makefile for ARM Streamline - Gator Daemon
3#
4
5# Uncomment and define CROSS_COMPILE if it is not already defined
6# CROSS_COMPILE=/path/to/cross-compiler/arm-linux-gnueabihf-
7# NOTE: This toolchain uses the hardfloat abi by default. For non-hardfloat
8# targets run 'make SOFTFLOAT=1 SYSROOT=/path/to/sysroot', see
9# README_Streamline.txt for more details
10
11CC = $(CROSS_COMPILE)gcc
12CXX = $(CROSS_COMPILE)g++
13
14# -mthumb-interwork is required for interworking to ARM or Thumb stdlibc
15CPPFLAGS += -mthumb-interwork
16
17ifeq ($(SOFTFLOAT),1)
18 CPPFLAGS += -marm -march=armv4t -mfloat-abi=soft
19 LDFLAGS += -marm -march=armv4t -mfloat-abi=soft
20endif
21ifneq ($(SYSROOT),)
22 LDFLAGS += --sysroot=$(SYSROOT)
23endif
24
25include common.mk
diff --git a/tools/gator/daemon/Makefile_aarch64 b/tools/gator/daemon/Makefile_aarch64
new file mode 100644
index 00000000000..efd1fa00218
--- /dev/null
+++ b/tools/gator/daemon/Makefile_aarch64
@@ -0,0 +1,12 @@
1#
2# Makefile for ARM Streamline - Gator Daemon
3# make -f Makefile_aarch64
4#
5
6# Uncomment and define CROSS_COMPILE if it is not already defined
7# CROSS_COMPILE=/path/to/cross-compiler/aarch64-linux-gnu-
8
9CC = $(CROSS_COMPILE)gcc
10CXX = $(CROSS_COMPILE)g++
11
12include common.mk
diff --git a/tools/gator/daemon/MaliVideoDriver.cpp b/tools/gator/daemon/MaliVideoDriver.cpp
new file mode 100644
index 00000000000..18b413b01a3
--- /dev/null
+++ b/tools/gator/daemon/MaliVideoDriver.cpp
@@ -0,0 +1,253 @@
1/**
2 * Copyright (C) ARM Limited 2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "MaliVideoDriver.h"
10
11#include <unistd.h>
12
13#include "Buffer.h"
14#include "Counter.h"
15#include "Logging.h"
16#include "SessionData.h"
17
18// From instr/src/mve_instr_comm_protocol.h
19typedef enum mve_instr_configuration_type {
20 MVE_INSTR_RAW = 1 << 0,
21 MVE_INSTR_COUNTERS = 1 << 1,
22 MVE_INSTR_EVENTS = 1 << 2,
23 MVE_INSTR_ACTIVITIES = 1 << 3,
24
25 // Raw always pushed regardless
26 MVE_INSTR_PULL = 1 << 12,
27 // Raw always unpacked regardless
28 MVE_INSTR_PACKED_COMM = 1 << 13,
29 // Don’t send ACKt response
30 MVE_INSTR_NO_AUTO_ACK = 1 << 14,
31} mve_instr_configuration_type_t;
32
33static const char COUNTER[] = "ARM_Mali-V500_cnt";
34static const char EVENT[] = "ARM_Mali-V500_evn";
35static const char ACTIVITY[] = "ARM_Mali-V500_act";
36
37class MaliVideoCounter {
38public:
39 MaliVideoCounter(MaliVideoCounter *next, const char *name, const MaliVideoCounterType type, const int id) : mNext(next), mName(name), mType(type), mId(id), mKey(getEventKey()), mEnabled(false) {
40 }
41
42 ~MaliVideoCounter() {
43 delete mName;
44 }
45
46 MaliVideoCounter *getNext() const { return mNext; }
47 const char *getName() const { return mName; }
48 MaliVideoCounterType getType() const { return mType; }
49 int getId() const { return mId; }
50 int getKey() const { return mKey; }
51 bool isEnabled() const { return mEnabled; }
52 void setEnabled(const bool enabled) { mEnabled = enabled; }
53
54private:
55 MaliVideoCounter *const mNext;
56 const char *const mName;
57 const MaliVideoCounterType mType;
58 // Mali Video id
59 const int mId;
60 // Streamline key
61 const int mKey;
62 bool mEnabled;
63};
64
65MaliVideoDriver::MaliVideoDriver() : mCounters(NULL), mActivityCount(0) {
66}
67
68MaliVideoDriver::~MaliVideoDriver() {
69 while (mCounters != NULL) {
70 MaliVideoCounter *counter = mCounters;
71 mCounters = counter->getNext();
72 delete counter;
73 }
74}
75
76void MaliVideoDriver::setup(mxml_node_t *const xml) {
77 // hwmon does not currently work with perf
78 if (gSessionData->perf.isSetup()) {
79 return;
80 }
81
82 mxml_node_t *node = xml;
83 while (true) {
84 node = mxmlFindElement(node, xml, "event", NULL, NULL, MXML_DESCEND);
85 if (node == NULL) {
86 break;
87 }
88 const char *counter = mxmlElementGetAttr(node, "counter");
89 if (counter == NULL) {
90 // Ignore
91 } else if (strncmp(counter, COUNTER, sizeof(COUNTER) - 1) == 0) {
92 const int i = strtol(counter + sizeof(COUNTER) - 1, NULL, 10);
93 mCounters = new MaliVideoCounter(mCounters, strdup(counter), MVCT_COUNTER, i);
94 } else if (strncmp(counter, EVENT, sizeof(EVENT) - 1) == 0) {
95 const int i = strtol(counter + sizeof(EVENT) - 1, NULL, 10);
96 mCounters = new MaliVideoCounter(mCounters, strdup(counter), MVCT_EVENT, i);
97 } else if (strcmp(counter, ACTIVITY) == 0) {
98 mCounters = new MaliVideoCounter(mCounters, strdup(ACTIVITY), MVCT_ACTIVITY, 0);
99 mActivityCount = 0;
100 while (true) {
101 char buf[32];
102 snprintf(buf, sizeof(buf), "activity%i", mActivityCount + 1);
103 if (mxmlElementGetAttr(node, buf) == NULL) {
104 break;
105 }
106 ++mActivityCount;
107 }
108 }
109 }
110}
111
112MaliVideoCounter *MaliVideoDriver::findCounter(const Counter &counter) const {
113 for (MaliVideoCounter *maliVideoCounter = mCounters; maliVideoCounter != NULL; maliVideoCounter = maliVideoCounter->getNext()) {
114 if (strcmp(maliVideoCounter->getName(), counter.getType()) == 0) {
115 return maliVideoCounter;
116 }
117 }
118
119 return NULL;
120}
121
122bool MaliVideoDriver::claimCounter(const Counter &counter) const {
123 return findCounter(counter) != NULL;
124}
125
126bool MaliVideoDriver::countersEnabled() const {
127 for (MaliVideoCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) {
128 if (counter->isEnabled()) {
129 return true;
130 }
131 }
132 return false;
133}
134
135void MaliVideoDriver::resetCounters() {
136 for (MaliVideoCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) {
137 counter->setEnabled(false);
138 }
139}
140
141void MaliVideoDriver::setupCounter(Counter &counter) {
142 MaliVideoCounter *const maliVideoCounter = findCounter(counter);
143 if (maliVideoCounter == NULL) {
144 counter.setEnabled(false);
145 return;
146 }
147 maliVideoCounter->setEnabled(true);
148 counter.setKey(maliVideoCounter->getKey());
149}
150
151int MaliVideoDriver::writeCounters(mxml_node_t *root) const {
152 if (access("/dev/mv500", F_OK) != 0) {
153 return 0;
154 }
155
156 int count = 0;
157 for (MaliVideoCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) {
158 mxml_node_t *node = mxmlNewElement(root, "counter");
159 mxmlElementSetAttr(node, "name", counter->getName());
160 ++count;
161 }
162
163 return count;
164}
165
166void MaliVideoDriver::marshalEnable(const MaliVideoCounterType type, char *const buf, const size_t bufsize, int &pos) {
167 // size
168 int numEnabled = 0;
169 for (MaliVideoCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) {
170 if (counter->isEnabled() && (counter->getType() == type)) {
171 ++numEnabled;
172 }
173 }
174 Buffer::packInt(buf, bufsize, pos, numEnabled*sizeof(uint32_t));
175 for (MaliVideoCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) {
176 if (counter->isEnabled() && (counter->getType() == type)) {
177 Buffer::packInt(buf, bufsize, pos, counter->getId());
178 }
179 }
180}
181
182bool MaliVideoDriver::start(const int mveUds) {
183 char buf[256];
184 int pos = 0;
185
186 // code - MVE_INSTR_STARTUP
187 buf[pos++] = 'C';
188 buf[pos++] = 'L';
189 buf[pos++] = 'N';
190 buf[pos++] = 'T';
191 // size
192 Buffer::packInt(buf, sizeof(buf), pos, sizeof(uint32_t));
193 // client_version_number
194 Buffer::packInt(buf, sizeof(buf), pos, 1);
195
196 // code - MVE_INSTR_CONFIGURE
197 buf[pos++] = 'C';
198 buf[pos++] = 'N';
199 buf[pos++] = 'F';
200 buf[pos++] = 'G';
201 // size
202 Buffer::packInt(buf, sizeof(buf), pos, 5*sizeof(uint32_t));
203 // configuration
204 Buffer::packInt(buf, sizeof(buf), pos, MVE_INSTR_COUNTERS | MVE_INSTR_EVENTS | MVE_INSTR_ACTIVITIES | MVE_INSTR_PACKED_COMM);
205 // communication_protocol_version
206 Buffer::packInt(buf, sizeof(buf), pos, 1);
207 // data_protocol_version
208 Buffer::packInt(buf, sizeof(buf), pos, 1);
209 // sample_rate - convert samples/second to ms/sample
210 Buffer::packInt(buf, sizeof(buf), pos, 1000/gSessionData->mSampleRate);
211 // live_rate - convert ns/flush to ms/flush
212 Buffer::packInt(buf, sizeof(buf), pos, gSessionData->mLiveRate/1000000);
213
214 // code - MVE_INSTR_ENABLE_COUNTERS
215 buf[pos++] = 'C';
216 buf[pos++] = 'F';
217 buf[pos++] = 'G';
218 buf[pos++] = 'c';
219 marshalEnable(MVCT_COUNTER, buf, sizeof(buf), pos);
220
221 // code - MVE_INSTR_ENABLE_EVENTS
222 buf[pos++] = 'C';
223 buf[pos++] = 'F';
224 buf[pos++] = 'G';
225 buf[pos++] = 'e';
226 marshalEnable(MVCT_EVENT, buf, sizeof(buf), pos);
227
228 /*
229 // code - MVE_INSTR_ENABLE_ACTIVITIES
230 buf[pos++] = 'C';
231 buf[pos++] = 'F';
232 buf[pos++] = 'G';
233 buf[pos++] = 'a';
234 // size
235 Buffer::packInt(buf, sizeof(buf), pos, mActivityCount*sizeof(uint32_t));
236 for (int i = 0; i < mActivityCount; ++i) {
237 // activity_id
238 Buffer::packInt(buf, sizeof(buf), pos, i);
239 }
240 */
241
242 int written = 0;
243 while (written < pos) {
244 size_t bytes = ::write(mveUds, buf + written, pos - written);
245 if (bytes <= 0) {
246 logg->logMessage("%s(%s:%i): write failed", __FUNCTION__, __FILE__, __LINE__);
247 return false;
248 }
249 written += bytes;
250 }
251
252 return true;
253}
diff --git a/tools/gator/daemon/MaliVideoDriver.h b/tools/gator/daemon/MaliVideoDriver.h
new file mode 100644
index 00000000000..00cb80889a7
--- /dev/null
+++ b/tools/gator/daemon/MaliVideoDriver.h
@@ -0,0 +1,50 @@
1/**
2 * Copyright (C) ARM Limited 2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef MALIVIDEODRIVER_H
10#define MALIVIDEODRIVER_H
11
12#include "Driver.h"
13
14class MaliVideoCounter;
15
16enum MaliVideoCounterType {
17 MVCT_COUNTER,
18 MVCT_EVENT,
19 MVCT_ACTIVITY,
20};
21
22class MaliVideoDriver : public Driver {
23public:
24 MaliVideoDriver();
25 ~MaliVideoDriver();
26
27 void setup(mxml_node_t *const xml);
28
29 bool claimCounter(const Counter &counter) const;
30 bool countersEnabled() const;
31 void resetCounters();
32 void setupCounter(Counter &counter);
33
34 int writeCounters(mxml_node_t *root) const;
35
36 bool start(const int mveUds);
37
38private:
39 MaliVideoCounter *findCounter(const Counter &counter) const;
40 void marshalEnable(const MaliVideoCounterType type, char *const buf, const size_t bufsize, int &pos);
41
42 MaliVideoCounter *mCounters;
43 int mActivityCount;
44
45 // Intentionally unimplemented
46 MaliVideoDriver(const MaliVideoDriver &);
47 MaliVideoDriver &operator=(const MaliVideoDriver &);
48};
49
50#endif // MALIVIDEODRIVER_H
diff --git a/tools/gator/daemon/Monitor.cpp b/tools/gator/daemon/Monitor.cpp
new file mode 100644
index 00000000000..b34a15f0eb0
--- /dev/null
+++ b/tools/gator/daemon/Monitor.cpp
@@ -0,0 +1,68 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "Monitor.h"
10
11#include <errno.h>
12#include <string.h>
13#include <unistd.h>
14
15#include "Logging.h"
16
17Monitor::Monitor() : mFd(-1) {
18}
19
20Monitor::~Monitor() {
21 if (mFd >= 0) {
22 ::close(mFd);
23 }
24}
25
26void Monitor::close() {
27 if (mFd >= 0) {
28 ::close(mFd);
29 mFd = -1;
30 }
31}
32
33bool Monitor::init() {
34 mFd = epoll_create(16);
35 if (mFd < 0) {
36 logg->logMessage("%s(%s:%i): epoll_create1 failed", __FUNCTION__, __FILE__, __LINE__);
37 return false;
38 }
39
40 return true;
41}
42
43bool Monitor::add(const int fd) {
44 struct epoll_event event;
45 memset(&event, 0, sizeof(event));
46 event.data.fd = fd;
47 event.events = EPOLLIN;
48 if (epoll_ctl(mFd, EPOLL_CTL_ADD, fd, &event) != 0) {
49 logg->logMessage("%s(%s:%i): epoll_ctl failed", __FUNCTION__, __FILE__, __LINE__);
50 return false;
51 }
52
53 return true;
54}
55
56int Monitor::wait(struct epoll_event *const events, int maxevents, int timeout) {
57 int result = epoll_wait(mFd, events, maxevents, timeout);
58 if (result < 0) {
59 // Ignore if the call was interrupted as this will happen when SIGINT is received
60 if (errno == EINTR) {
61 result = 0;
62 } else {
63 logg->logMessage("%s(%s:%i): epoll_wait failed", __FUNCTION__, __FILE__, __LINE__);
64 }
65 }
66
67 return result;
68}
diff --git a/tools/gator/daemon/Monitor.h b/tools/gator/daemon/Monitor.h
new file mode 100644
index 00000000000..7194e0e4ca5
--- /dev/null
+++ b/tools/gator/daemon/Monitor.h
@@ -0,0 +1,33 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef MONITOR_H
10#define MONITOR_H
11
12#include <sys/epoll.h>
13
14class Monitor {
15public:
16 Monitor();
17 ~Monitor();
18
19 void close();
20 bool init();
21 bool add(const int fd);
22 int wait(struct epoll_event *const events, int maxevents, int timeout);
23
24private:
25
26 int mFd;
27
28 // Intentionally unimplemented
29 Monitor(const Monitor &);
30 Monitor &operator=(const Monitor &);
31};
32
33#endif // MONITOR_H
diff --git a/tools/gator/daemon/OlySocket.cpp b/tools/gator/daemon/OlySocket.cpp
new file mode 100644
index 00000000000..28774e36e51
--- /dev/null
+++ b/tools/gator/daemon/OlySocket.cpp
@@ -0,0 +1,282 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "OlySocket.h"
10
11#include <stdio.h>
12#include <string.h>
13#ifdef WIN32
14#include <Winsock2.h>
15#include <ws2tcpip.h>
16#else
17#include <netinet/in.h>
18#include <sys/socket.h>
19#include <sys/un.h>
20#include <unistd.h>
21#include <netdb.h>
22#endif
23
24#include "Logging.h"
25
26#ifdef WIN32
27#define CLOSE_SOCKET(x) closesocket(x)
28#define SHUTDOWN_RX_TX SD_BOTH
29#define snprintf _snprintf
30#else
31#define CLOSE_SOCKET(x) close(x)
32#define SHUTDOWN_RX_TX SHUT_RDWR
33#endif
34
35OlyServerSocket::OlyServerSocket(int port) {
36#ifdef WIN32
37 WSADATA wsaData;
38 if (WSAStartup(0x0202, &wsaData) != 0) {
39 logg->logError(__FILE__, __LINE__, "Windows socket initialization failed");
40 handleException();
41 }
42#endif
43
44 createServerSocket(port);
45}
46
47OlySocket::OlySocket(int socketID) : mSocketID(socketID) {
48}
49
50#ifndef WIN32
51
52#define MIN(A, B) ({ \
53 const __typeof__(A) __a = A; \
54 const __typeof__(B) __b = B; \
55 __a > __b ? __b : __a; \
56})
57
58OlyServerSocket::OlyServerSocket(const char* path, const size_t pathSize) {
59 // Create socket
60 mFDServer = socket(PF_UNIX, SOCK_STREAM, 0);
61 if (mFDServer < 0) {
62 logg->logError(__FILE__, __LINE__, "Error creating server socket");
63 handleException();
64 }
65
66 // Create sockaddr_in structure, ensuring non-populated fields are zero
67 struct sockaddr_un sockaddr;
68 memset((void*)&sockaddr, 0, sizeof(sockaddr));
69 sockaddr.sun_family = AF_UNIX;
70 memcpy(sockaddr.sun_path, path, MIN(pathSize, sizeof(sockaddr.sun_path)));
71 sockaddr.sun_path[sizeof(sockaddr.sun_path) - 1] = '\0';
72
73 // Bind the socket to an address
74 if (bind(mFDServer, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) {
75 logg->logError(__FILE__, __LINE__, "Binding of server socket failed.");
76 handleException();
77 }
78
79 // Listen for connections on this socket
80 if (listen(mFDServer, 1) < 0) {
81 logg->logError(__FILE__, __LINE__, "Listening of server socket failed");
82 handleException();
83 }
84}
85
86int OlySocket::connect(const char* path, const size_t pathSize) {
87 int fd = socket(PF_UNIX, SOCK_STREAM, 0);
88 if (fd < 0) {
89 return -1;
90 }
91
92 // Create sockaddr_in structure, ensuring non-populated fields are zero
93 struct sockaddr_un sockaddr;
94 memset((void*)&sockaddr, 0, sizeof(sockaddr));
95 sockaddr.sun_family = AF_UNIX;
96 memcpy(sockaddr.sun_path, path, MIN(pathSize, sizeof(sockaddr.sun_path)));
97 sockaddr.sun_path[sizeof(sockaddr.sun_path) - 1] = '\0';
98
99 if (::connect(fd, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) {
100 close(fd);
101 return -1;
102 }
103
104 return fd;
105}
106
107#endif
108
109OlySocket::~OlySocket() {
110 if (mSocketID > 0) {
111 CLOSE_SOCKET(mSocketID);
112 }
113}
114
115OlyServerSocket::~OlyServerSocket() {
116 if (mFDServer > 0) {
117 CLOSE_SOCKET(mFDServer);
118 }
119}
120
121void OlySocket::shutdownConnection() {
122 // Shutdown is primarily used to unblock other threads that are blocking on send/receive functions
123 shutdown(mSocketID, SHUTDOWN_RX_TX);
124}
125
126void OlySocket::closeSocket() {
127 // Used for closing an accepted socket but keeping the server socket active
128 if (mSocketID > 0) {
129 CLOSE_SOCKET(mSocketID);
130 mSocketID = -1;
131 }
132}
133
134void OlyServerSocket::closeServerSocket() {
135 if (CLOSE_SOCKET(mFDServer) != 0) {
136 logg->logError(__FILE__, __LINE__, "Failed to close server socket.");
137 handleException();
138 }
139 mFDServer = 0;
140}
141
142void OlyServerSocket::createServerSocket(int port) {
143 int family = AF_INET6;
144
145 // Create socket
146 mFDServer = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
147 if (mFDServer < 0) {
148 family = AF_INET;
149 mFDServer = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
150 if (mFDServer < 0) {
151 logg->logError(__FILE__, __LINE__, "Error creating server socket");
152 handleException();
153 }
154 }
155
156 // Enable address reuse, another solution would be to create the server socket once and only close it when the object exits
157 int on = 1;
158 if (setsockopt(mFDServer, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)) != 0) {
159 logg->logError(__FILE__, __LINE__, "Setting server socket options failed");
160 handleException();
161 }
162
163 // Create sockaddr_in structure, ensuring non-populated fields are zero
164 struct sockaddr_in6 sockaddr;
165 memset((void*)&sockaddr, 0, sizeof(sockaddr));
166 sockaddr.sin6_family = family;
167 sockaddr.sin6_port = htons(port);
168 sockaddr.sin6_addr = in6addr_any;
169
170 // Bind the socket to an address
171 if (bind(mFDServer, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) {
172 logg->logError(__FILE__, __LINE__, "Binding of server socket failed.\nIs an instance already running?");
173 handleException();
174 }
175
176 // Listen for connections on this socket
177 if (listen(mFDServer, 1) < 0) {
178 logg->logError(__FILE__, __LINE__, "Listening of server socket failed");
179 handleException();
180 }
181}
182
183// mSocketID is always set to the most recently accepted connection
184// The user of this class should maintain the different socket connections, e.g. by forking the process
185int OlyServerSocket::acceptConnection() {
186 int socketID;
187 if (mFDServer <= 0) {
188 logg->logError(__FILE__, __LINE__, "Attempting multiple connections on a single connection server socket or attempting to accept on a client socket");
189 handleException();
190 }
191
192 // Accept a connection, note that this call blocks until a client connects
193 socketID = accept(mFDServer, NULL, NULL);
194 if (socketID < 0) {
195 logg->logError(__FILE__, __LINE__, "Socket acceptance failed");
196 handleException();
197 }
198 return socketID;
199}
200
201void OlySocket::send(const char* buffer, int size) {
202 if (size <= 0 || buffer == NULL) {
203 return;
204 }
205
206 while (size > 0) {
207 int n = ::send(mSocketID, buffer, size, 0);
208 if (n < 0) {
209 logg->logError(__FILE__, __LINE__, "Socket send error");
210 handleException();
211 }
212 size -= n;
213 buffer += n;
214 }
215}
216
217// Returns the number of bytes received
218int OlySocket::receive(char* buffer, int size) {
219 if (size <= 0 || buffer == NULL) {
220 return 0;
221 }
222
223 int bytes = recv(mSocketID, buffer, size, 0);
224 if (bytes < 0) {
225 logg->logError(__FILE__, __LINE__, "Socket receive error");
226 handleException();
227 } else if (bytes == 0) {
228 logg->logMessage("Socket disconnected");
229 return -1;
230 }
231 return bytes;
232}
233
234// Receive exactly size bytes of data. Note, this function will block until all bytes are received
235int OlySocket::receiveNBytes(char* buffer, int size) {
236 int bytes = 0;
237 while (size > 0 && buffer != NULL) {
238 bytes = recv(mSocketID, buffer, size, 0);
239 if (bytes < 0) {
240 logg->logError(__FILE__, __LINE__, "Socket receive error");
241 handleException();
242 } else if (bytes == 0) {
243 logg->logMessage("Socket disconnected");
244 return -1;
245 }
246 buffer += bytes;
247 size -= bytes;
248 }
249 return bytes;
250}
251
252// Receive data until a carriage return, line feed, or null is encountered, or the buffer fills
253int OlySocket::receiveString(char* buffer, int size) {
254 int bytes_received = 0;
255 bool found = false;
256
257 if (buffer == 0) {
258 return 0;
259 }
260
261 while (!found && bytes_received < size) {
262 // Receive a single character
263 int bytes = recv(mSocketID, &buffer[bytes_received], 1, 0);
264 if (bytes < 0) {
265 logg->logError(__FILE__, __LINE__, "Socket receive error");
266 handleException();
267 } else if (bytes == 0) {
268 logg->logMessage("Socket disconnected");
269 return -1;
270 }
271
272 // Replace carriage returns and line feeds with zero
273 if (buffer[bytes_received] == '\n' || buffer[bytes_received] == '\r' || buffer[bytes_received] == '\0') {
274 buffer[bytes_received] = '\0';
275 found = true;
276 }
277
278 bytes_received++;
279 }
280
281 return bytes_received;
282}
diff --git a/tools/gator/daemon/OlySocket.h b/tools/gator/daemon/OlySocket.h
new file mode 100644
index 00000000000..20c67cc695e
--- /dev/null
+++ b/tools/gator/daemon/OlySocket.h
@@ -0,0 +1,55 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef __OLY_SOCKET_H__
10#define __OLY_SOCKET_H__
11
12#include <stddef.h>
13
14class OlySocket {
15public:
16#ifndef WIN32
17 static int connect(const char* path, const size_t pathSize);
18#endif
19
20 OlySocket(int socketID);
21 ~OlySocket();
22
23 void closeSocket();
24 void shutdownConnection();
25 void send(const char* buffer, int size);
26 int receive(char* buffer, int size);
27 int receiveNBytes(char* buffer, int size);
28 int receiveString(char* buffer, int size);
29
30 bool isValid() const { return mSocketID >= 0; }
31
32private:
33 int mSocketID;
34};
35
36class OlyServerSocket {
37public:
38 OlyServerSocket(int port);
39#ifndef WIN32
40 OlyServerSocket(const char* path, const size_t pathSize);
41#endif
42 ~OlyServerSocket();
43
44 int acceptConnection();
45 void closeServerSocket();
46
47 int getFd() { return mFDServer; }
48
49private:
50 int mFDServer;
51
52 void createServerSocket(int port);
53};
54
55#endif //__OLY_SOCKET_H__
diff --git a/tools/gator/daemon/OlyUtility.cpp b/tools/gator/daemon/OlyUtility.cpp
new file mode 100644
index 00000000000..45340a27d9f
--- /dev/null
+++ b/tools/gator/daemon/OlyUtility.cpp
@@ -0,0 +1,227 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "OlyUtility.h"
10
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <ctype.h>
15
16#if defined(WIN32)
17#include <windows.h>
18#elif defined(__linux__)
19#include <unistd.h>
20#elif defined(DARWIN)
21#include <mach-o/dyld.h>
22#endif
23
24OlyUtility* util = NULL;
25
26bool OlyUtility::stringToBool(const char* string, bool defValue) {
27 char value[32];
28
29 if (string == NULL) {
30 return defValue;
31 }
32
33 strncpy(value, string, sizeof(value));
34 if (value[0] == 0) {
35 return defValue;
36 }
37 value[sizeof(value) - 1] = 0; // strncpy does not guarantee a null-terminated string
38
39 // Convert to lowercase
40 int i = 0;
41 while (value[i]) {
42 value[i] = tolower(value[i]);
43 i++;
44 }
45
46 if (strcmp(value, "true") == 0 || strcmp(value, "yes") == 0 || strcmp(value, "1") == 0 || strcmp(value, "on") == 0) {
47 return true;
48 } else if (strcmp(value, "false") == 0 || strcmp(value, "no") == 0 || strcmp(value, "0") == 0 || strcmp(value, "off") == 0) {
49 return false;
50 } else {
51 return defValue;
52 }
53}
54
55void OlyUtility::stringToLower(char* string) {
56 if (string == NULL) {
57 return;
58 }
59
60 while (*string) {
61 *string = tolower(*string);
62 string++;
63 }
64}
65
66// Modifies fullpath with the path part including the trailing path separator
67int OlyUtility::getApplicationFullPath(char* fullpath, int sizeOfPath) {
68 memset(fullpath, 0, sizeOfPath);
69#if defined(WIN32)
70 int length = GetModuleFileName(NULL, fullpath, sizeOfPath);
71#elif defined(__linux__)
72 int length = readlink("/proc/self/exe", fullpath, sizeOfPath);
73#elif defined(DARWIN)
74 uint32_t length_u = (uint32_t)sizeOfPath;
75 int length = sizeOfPath;
76 if (_NSGetExecutablePath(fullpath, &length_u) == 0) {
77 length = strlen(fullpath);
78 }
79#endif
80
81 if (length == sizeOfPath) {
82 return -1;
83 }
84
85 fullpath[length] = 0;
86 getPathPart(fullpath);
87
88 return 0;
89}
90
91char* OlyUtility::readFromDisk(const char* file, unsigned int *size, bool appendNull) {
92 // Open the file
93 FILE* pFile = fopen(file, "rb");
94 if (pFile==NULL) {
95 return NULL;
96 }
97
98 // Obtain file size
99 fseek(pFile , 0 , SEEK_END);
100 unsigned int lSize = ftell(pFile);
101 rewind(pFile);
102
103 // Allocate memory to contain the whole file
104 char* buffer = (char*)malloc(lSize + (int)appendNull);
105 if (buffer == NULL) {
106 fclose(pFile);
107 return NULL;
108 }
109
110 // Copy the file into the buffer
111 if (fread(buffer, 1, lSize, pFile) != lSize) {
112 free(buffer);
113 fclose(pFile);
114 return NULL;
115 }
116
117 // Terminate
118 fclose(pFile);
119
120 if (appendNull) {
121 buffer[lSize] = 0;
122 }
123
124 if (size) {
125 *size = lSize;
126 }
127
128 return buffer;
129}
130
131int OlyUtility::writeToDisk(const char* path, const char* data) {
132 // Open the file
133 FILE* pFile = fopen(path, "wb");
134 if (pFile == NULL) {
135 return -1;
136 }
137
138 // Write the data to disk
139 if (fwrite(data, 1, strlen(data), pFile) != strlen(data)) {
140 fclose(pFile);
141 return -1;
142 }
143
144 // Terminate
145 fclose(pFile);
146 return 0;
147}
148
149int OlyUtility::appendToDisk(const char* path, const char* data) {
150 // Open the file
151 FILE* pFile = fopen(path, "a");
152 if (pFile == NULL) {
153 return -1;
154 }
155
156 // Write the data to disk
157 if (fwrite(data, 1, strlen(data), pFile) != strlen(data)) {
158 fclose(pFile);
159 return -1;
160 }
161
162 // Terminate
163 fclose(pFile);
164 return 0;
165}
166
167/**
168 * Copies the srcFile into dstFile in 1kB chunks.
169 * The dstFile will be overwritten if it exists.
170 * 0 is returned on an error; otherwise 1.
171 */
172#define TRANSFER_SIZE 1024
173int OlyUtility::copyFile(const char* srcFile, const char* dstFile) {
174 char buffer[TRANSFER_SIZE];
175 FILE * f_src = fopen(srcFile,"rb");
176 if (!f_src) {
177 return 0;
178 }
179 FILE * f_dst = fopen(dstFile,"wb");
180 if (!f_dst) {
181 fclose(f_src);
182 return 0;
183 }
184 while (!feof(f_src)) {
185 int num_bytes_read = fread(buffer, 1, TRANSFER_SIZE, f_src);
186 if (num_bytes_read < TRANSFER_SIZE && !feof(f_src)) {
187 fclose(f_src);
188 fclose(f_dst);
189 return 0;
190 }
191 int num_bytes_written = fwrite(buffer, 1, num_bytes_read, f_dst);
192 if (num_bytes_written != num_bytes_read) {
193 fclose(f_src);
194 fclose(f_dst);
195 return 0;
196 }
197 }
198 fclose(f_src);
199 fclose(f_dst);
200 return 1;
201}
202
203const char* OlyUtility::getFilePart(const char* path) {
204 const char* last_sep = strrchr(path, PATH_SEPARATOR);
205
206 // in case path is not a full path
207 if (last_sep == NULL) {
208 return path;
209 }
210
211 return last_sep++;
212}
213
214// getPathPart may modify the contents of path
215// returns the path including the trailing path separator
216char* OlyUtility::getPathPart(char* path) {
217 char* last_sep = strrchr(path, PATH_SEPARATOR);
218
219 // in case path is not a full path
220 if (last_sep == NULL) {
221 return 0;
222 }
223 last_sep++;
224 *last_sep = 0;
225
226 return (path);
227}
diff --git a/tools/gator/daemon/OlyUtility.h b/tools/gator/daemon/OlyUtility.h
new file mode 100644
index 00000000000..1d26beb596f
--- /dev/null
+++ b/tools/gator/daemon/OlyUtility.h
@@ -0,0 +1,42 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef OLY_UTILITY_H
10#define OLY_UTILITY_H
11
12#include <stddef.h>
13
14#ifdef WIN32
15#define PATH_SEPARATOR '\\'
16#define CAIMAN_PATH_MAX MAX_PATH
17#define snprintf _snprintf
18#else
19#include <limits.h>
20#define PATH_SEPARATOR '/'
21#define CAIMAN_PATH_MAX PATH_MAX
22#endif
23
24class OlyUtility {
25public:
26 OlyUtility() {};
27 ~OlyUtility() {};
28 bool stringToBool(const char* string, bool defValue);
29 void stringToLower(char* string);
30 int getApplicationFullPath(char* path, int sizeOfPath);
31 char* readFromDisk(const char* file, unsigned int *size = NULL, bool appendNull = true);
32 int writeToDisk(const char* path, const char* file);
33 int appendToDisk(const char* path, const char* file);
34 int copyFile(const char* srcFile, const char* dstFile);
35 const char* getFilePart(const char* path);
36 char* getPathPart(char* path);
37private:
38};
39
40extern OlyUtility* util;
41
42#endif // OLY_UTILITY_H
diff --git a/tools/gator/daemon/PerfBuffer.cpp b/tools/gator/daemon/PerfBuffer.cpp
new file mode 100644
index 00000000000..5fad583f7bd
--- /dev/null
+++ b/tools/gator/daemon/PerfBuffer.cpp
@@ -0,0 +1,139 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "PerfBuffer.h"
10
11#include <sys/ioctl.h>
12#include <sys/mman.h>
13
14#include "Buffer.h"
15#include "Logging.h"
16#include "Sender.h"
17#include "SessionData.h"
18
19PerfBuffer::PerfBuffer() {
20 for (int cpu = 0; cpu < ARRAY_LENGTH(mBuf); ++cpu) {
21 mBuf[cpu] = MAP_FAILED;
22 mDiscard[cpu] = false;
23 }
24}
25
26PerfBuffer::~PerfBuffer() {
27 for (int cpu = ARRAY_LENGTH(mBuf) - 1; cpu >= 0; --cpu) {
28 if (mBuf[cpu] != MAP_FAILED) {
29 munmap(mBuf[cpu], gSessionData->mPageSize + BUF_SIZE);
30 }
31 }
32}
33
34bool PerfBuffer::useFd(const int cpu, const int fd, const int groupFd) {
35 if (fd == groupFd) {
36 if (mBuf[cpu] != MAP_FAILED) {
37 logg->logMessage("%s(%s:%i): cpu %i already online or not correctly cleaned up", __FUNCTION__, __FILE__, __LINE__, cpu);
38 return false;
39 }
40
41 // The buffer isn't mapped yet
42 mBuf[cpu] = mmap(NULL, gSessionData->mPageSize + BUF_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
43 if (mBuf[cpu] == MAP_FAILED) {
44 logg->logMessage("%s(%s:%i): mmap failed", __FUNCTION__, __FILE__, __LINE__);
45 return false;
46 }
47
48 // Check the version
49 struct perf_event_mmap_page *pemp = static_cast<struct perf_event_mmap_page *>(mBuf[cpu]);
50 if (pemp->compat_version != 0) {
51 logg->logMessage("%s(%s:%i): Incompatible perf_event_mmap_page compat_version", __FUNCTION__, __FILE__, __LINE__);
52 return false;
53 }
54 } else {
55 if (mBuf[cpu] == MAP_FAILED) {
56 logg->logMessage("%s(%s:%i): cpu already online or not correctly cleaned up", __FUNCTION__, __FILE__, __LINE__);
57 return false;
58 }
59
60 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, groupFd) < 0) {
61 logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
62 return false;
63 }
64 }
65
66 return true;
67}
68
69void PerfBuffer::discard(const int cpu) {
70 if (mBuf[cpu] != MAP_FAILED) {
71 mDiscard[cpu] = true;
72 }
73}
74
75bool PerfBuffer::isEmpty() {
76 for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
77 if (mBuf[cpu] != MAP_FAILED) {
78 // Take a snapshot of the positions
79 struct perf_event_mmap_page *pemp = static_cast<struct perf_event_mmap_page *>(mBuf[cpu]);
80 const __u64 head = pemp->data_head;
81 const __u64 tail = pemp->data_tail;
82
83 if (head != tail) {
84 return false;
85 }
86 }
87 }
88
89 return true;
90}
91
92bool PerfBuffer::send(Sender *const sender) {
93 for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
94 if (mBuf[cpu] == MAP_FAILED) {
95 continue;
96 }
97
98 // Take a snapshot of the positions
99 struct perf_event_mmap_page *pemp = static_cast<struct perf_event_mmap_page *>(mBuf[cpu]);
100 const __u64 head = pemp->data_head;
101 const __u64 tail = pemp->data_tail;
102
103 if (head > tail) {
104 const uint8_t *const b = static_cast<uint8_t *>(mBuf[cpu]) + gSessionData->mPageSize;
105 const int offset = gSessionData->mLocalCapture ? 1 : 0;
106 unsigned char header[7];
107 header[0] = RESPONSE_APC_DATA;
108 Buffer::writeLEInt(header + 1, head - tail + sizeof(header) - 5);
109 // Should use real packing functions
110 header[5] = FRAME_PERF;
111 header[6] = cpu;
112
113 // Write header
114 sender->writeData(reinterpret_cast<const char *>(&header) + offset, sizeof(header) - offset, RESPONSE_APC_DATA);
115
116 // Write data
117 if ((head & ~BUF_MASK) == (tail & ~BUF_MASK)) {
118 // Not wrapped
119 sender->writeData(reinterpret_cast<const char *>(b + (tail & BUF_MASK)), head - tail, RESPONSE_APC_DATA);
120 } else {
121 // Wrapped
122 sender->writeData(reinterpret_cast<const char *>(b + (tail & BUF_MASK)), BUF_SIZE - (tail & BUF_MASK), RESPONSE_APC_DATA);
123 sender->writeData(reinterpret_cast<const char *>(b), head & BUF_MASK, RESPONSE_APC_DATA);
124 }
125
126 // Update tail with the data read
127 pemp->data_tail = head;
128 }
129
130 if (mDiscard[cpu]) {
131 munmap(mBuf[cpu], gSessionData->mPageSize + BUF_SIZE);
132 mBuf[cpu] = MAP_FAILED;
133 mDiscard[cpu] = false;
134 logg->logMessage("%s(%s:%i): Unmaped cpu %i", __FUNCTION__, __FILE__, __LINE__, cpu);
135 }
136 }
137
138 return true;
139}
diff --git a/tools/gator/daemon/PerfBuffer.h b/tools/gator/daemon/PerfBuffer.h
new file mode 100644
index 00000000000..278a3b9d6db
--- /dev/null
+++ b/tools/gator/daemon/PerfBuffer.h
@@ -0,0 +1,39 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef PERF_BUFFER
10#define PERF_BUFFER
11
12#include "Config.h"
13
14#define BUF_SIZE (gSessionData->mTotalBufferSize * 1024 * 1024)
15#define BUF_MASK (BUF_SIZE - 1)
16
17class Sender;
18
19class PerfBuffer {
20public:
21 PerfBuffer();
22 ~PerfBuffer();
23
24 bool useFd(const int cpu, const int fd, const int groupFd);
25 void discard(const int cpu);
26 bool isEmpty();
27 bool send(Sender *const sender);
28
29private:
30 void *mBuf[NR_CPUS];
31 // After the buffer is flushed it should be unmaped
32 bool mDiscard[NR_CPUS];
33
34 // Intentionally undefined
35 PerfBuffer(const PerfBuffer &);
36 PerfBuffer &operator=(const PerfBuffer &);
37};
38
39#endif // PERF_BUFFER
diff --git a/tools/gator/daemon/PerfDriver.cpp b/tools/gator/daemon/PerfDriver.cpp
new file mode 100644
index 00000000000..ac97a077d26
--- /dev/null
+++ b/tools/gator/daemon/PerfDriver.cpp
@@ -0,0 +1,409 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "PerfDriver.h"
10
11#include <dirent.h>
12#include <sys/utsname.h>
13#include <time.h>
14#include <unistd.h>
15
16#include "Buffer.h"
17#include "Config.h"
18#include "ConfigurationXML.h"
19#include "Counter.h"
20#include "DriverSource.h"
21#include "DynBuf.h"
22#include "Logging.h"
23#include "PerfGroup.h"
24#include "SessionData.h"
25
26#define PERF_DEVICES "/sys/bus/event_source/devices"
27
28#define TYPE_DERIVED ~0U
29
30// From gator.h
31struct gator_cpu {
32 const int cpuid;
33 // Human readable name
34 const char *const core_name;
35 // gatorfs event and Perf PMU name
36 const char *const pmnc_name;
37 const int pmnc_counters;
38};
39
40// From gator_main.c
41static const struct gator_cpu gator_cpus[] = {
42 { 0xb36, "ARM1136", "ARM_ARM11", 3 },
43 { 0xb56, "ARM1156", "ARM_ARM11", 3 },
44 { 0xb76, "ARM1176", "ARM_ARM11", 3 },
45 { 0xb02, "ARM11MPCore", "ARM_ARM11MPCore", 3 },
46 { 0xc05, "Cortex-A5", "ARMv7_Cortex_A5", 2 },
47 { 0xc07, "Cortex-A7", "ARMv7_Cortex_A7", 4 },
48 { 0xc08, "Cortex-A8", "ARMv7_Cortex_A8", 4 },
49 { 0xc09, "Cortex-A9", "ARMv7_Cortex_A9", 6 },
50 { 0xc0d, "Cortex-A12", "ARMv7_Cortex_A12", 6 },
51 { 0xc0f, "Cortex-A15", "ARMv7_Cortex_A15", 6 },
52 { 0xc0e, "Cortex-A17", "ARMv7_Cortex_A17", 6 },
53 { 0x00f, "Scorpion", "Scorpion", 4 },
54 { 0x02d, "ScorpionMP", "ScorpionMP", 4 },
55 { 0x049, "KraitSIM", "Krait", 4 },
56 { 0x04d, "Krait", "Krait", 4 },
57 { 0x06f, "Krait S4 Pro", "Krait", 4 },
58 { 0xd03, "Cortex-A53", "ARM_Cortex-A53", 6 },
59 { 0xd07, "Cortex-A57", "ARM_Cortex-A57", 6 },
60 { 0xd0f, "AArch64", "ARM_AArch64", 6 },
61};
62
63static const char OLD_PMU_PREFIX[] = "ARMv7 Cortex-";
64static const char NEW_PMU_PREFIX[] = "ARMv7_Cortex_";
65
66struct uncore_counter {
67 // gatorfs event and Perf PMU name
68 const char *const name;
69 const int count;
70};
71
72static const struct uncore_counter uncore_counters[] = {
73 { "CCI_400", 4 },
74 { "CCI_400-r1", 4 },
75};
76
77class PerfCounter {
78public:
79 PerfCounter(PerfCounter *next, const char *name, uint32_t type, uint64_t config, bool perCpu) : mNext(next), mName(name), mType(type), mCount(0), mKey(getEventKey()), mConfig(config), mEnabled(false), mPerCpu(perCpu) {}
80 ~PerfCounter() {
81 delete [] mName;
82 }
83
84 PerfCounter *getNext() const { return mNext; }
85 const char *getName() const { return mName; }
86 uint32_t getType() const { return mType; }
87 int getCount() const { return mCount; }
88 void setCount(const int count) { mCount = count; }
89 int getKey() const { return mKey; }
90 uint64_t getConfig() const { return mConfig; }
91 void setConfig(const uint64_t config) { mConfig = config; }
92 bool isEnabled() const { return mEnabled; }
93 void setEnabled(const bool enabled) { mEnabled = enabled; }
94 bool isPerCpu() const { return mPerCpu; }
95
96private:
97 PerfCounter *const mNext;
98 const char *const mName;
99 const uint32_t mType;
100 int mCount;
101 const int mKey;
102 uint64_t mConfig;
103 int mEnabled : 1,
104 mPerCpu : 1;
105};
106
107PerfDriver::PerfDriver() : mCounters(NULL), mIsSetup(false), mLegacySupport(false) {
108}
109
110PerfDriver::~PerfDriver() {
111 while (mCounters != NULL) {
112 PerfCounter *counter = mCounters;
113 mCounters = counter->getNext();
114 delete counter;
115 }
116}
117
118void PerfDriver::addCpuCounters(const char *const counterName, const int type, const int numCounters) {
119 int len = snprintf(NULL, 0, "%s_ccnt", counterName) + 1;
120 char *name = new char[len];
121 snprintf(name, len, "%s_ccnt", counterName);
122 mCounters = new PerfCounter(mCounters, name, type, -1, true);
123
124 for (int j = 0; j < numCounters; ++j) {
125 len = snprintf(NULL, 0, "%s_cnt%d", counterName, j) + 1;
126 name = new char[len];
127 snprintf(name, len, "%s_cnt%d", counterName, j);
128 mCounters = new PerfCounter(mCounters, name, type, -1, true);
129 }
130}
131
132void PerfDriver::addUncoreCounters(const char *const counterName, const int type, const int numCounters) {
133 int len = snprintf(NULL, 0, "%s_ccnt", counterName) + 1;
134 char *name = new char[len];
135 snprintf(name, len, "%s_ccnt", counterName);
136 mCounters = new PerfCounter(mCounters, name, type, -1, false);
137
138 for (int j = 0; j < numCounters; ++j) {
139 len = snprintf(NULL, 0, "%s_cnt%d", counterName, j) + 1;
140 name = new char[len];
141 snprintf(name, len, "%s_cnt%d", counterName, j);
142 mCounters = new PerfCounter(mCounters, name, type, -1, false);
143 }
144}
145
146// From include/generated/uapi/linux/version.h
147#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
148
149bool PerfDriver::setup() {
150 // Check the kernel version
151 struct utsname utsname;
152 if (uname(&utsname) != 0) {
153 logg->logMessage("%s(%s:%i): uname failed", __FUNCTION__, __FILE__, __LINE__);
154 return false;
155 }
156
157 int release[3] = { 0, 0, 0 };
158 int part = 0;
159 char *ch = utsname.release;
160 while (*ch >= '0' && *ch <= '9' && part < ARRAY_LENGTH(release)) {
161 release[part] = 10*release[part] + *ch - '0';
162
163 ++ch;
164 if (*ch == '.') {
165 ++part;
166 ++ch;
167 }
168 }
169
170 if (KERNEL_VERSION(release[0], release[1], release[2]) < KERNEL_VERSION(3, 4, 0)) {
171 logg->logMessage("%s(%s:%i): Unsupported kernel version", __FUNCTION__, __FILE__, __LINE__);
172 return false;
173 }
174 mLegacySupport = KERNEL_VERSION(release[0], release[1], release[2]) < KERNEL_VERSION(3, 12, 0);
175
176 if (access(EVENTS_PATH, R_OK) != 0) {
177 logg->logMessage("%s(%s:%i): " EVENTS_PATH " does not exist, is CONFIG_TRACING enabled?", __FUNCTION__, __FILE__, __LINE__);
178 return false;
179 }
180
181 // Add supported PMUs
182 bool foundCpu = false;
183 DIR *dir = opendir(PERF_DEVICES);
184 if (dir == NULL) {
185 logg->logMessage("%s(%s:%i): opendif failed", __FUNCTION__, __FILE__, __LINE__);
186 return false;
187 }
188
189 struct dirent *dirent;
190 while ((dirent = readdir(dir)) != NULL) {
191 for (int i = 0; i < ARRAY_LENGTH(gator_cpus); ++i) {
192 // Do the names match exactly?
193 if (strcmp(dirent->d_name, gator_cpus[i].pmnc_name) != 0 &&
194 // Do these names match but have the old vs new prefix?
195 (strncmp(dirent->d_name, OLD_PMU_PREFIX, sizeof(OLD_PMU_PREFIX) - 1) != 0 ||
196 strncmp(gator_cpus[i].pmnc_name, NEW_PMU_PREFIX, sizeof(NEW_PMU_PREFIX) - 1) != 0 ||
197 strcmp(dirent->d_name + sizeof(OLD_PMU_PREFIX) - 1, gator_cpus[i].pmnc_name + sizeof(NEW_PMU_PREFIX) - 1) != 0)) {
198 continue;
199 }
200
201 int type;
202 char buf[256];
203 snprintf(buf, sizeof(buf), PERF_DEVICES "/%s/type", dirent->d_name);
204 if (DriverSource::readIntDriver(buf, &type) != 0) {
205 continue;
206 }
207
208 foundCpu = true;
209 addCpuCounters(gator_cpus[i].pmnc_name, type, gator_cpus[i].pmnc_counters);
210 }
211
212 for (int i = 0; i < ARRAY_LENGTH(uncore_counters); ++i) {
213 if (strcmp(dirent->d_name, uncore_counters[i].name) != 0) {
214 continue;
215 }
216
217 int type;
218 char buf[256];
219 snprintf(buf, sizeof(buf), PERF_DEVICES "/%s/type", dirent->d_name);
220 if (DriverSource::readIntDriver(buf, &type) != 0) {
221 continue;
222 }
223
224 addUncoreCounters(uncore_counters[i].name, type, uncore_counters[i].count);
225 }
226 }
227 closedir(dir);
228
229 if (!foundCpu) {
230 // If no cpu was found based on pmu names, try by cpuid
231 for (int i = 0; i < ARRAY_LENGTH(gator_cpus); ++i) {
232 if (gSessionData->mMaxCpuId != gator_cpus[i].cpuid) {
233 continue;
234 }
235
236 foundCpu = true;
237 addCpuCounters(gator_cpus[i].pmnc_name, PERF_TYPE_RAW, gator_cpus[i].pmnc_counters);
238 }
239 }
240
241 /*
242 if (!foundCpu) {
243 // If all else fails, use the perf architected counters
244 // 9 because that's how many are in events-Perf-Hardware.xml - assume they can all be enabled at once
245 addCpuCounters("Perf_Hardware", PERF_TYPE_HARDWARE, 9);
246 }
247 */
248
249 // Add supported software counters
250 long long id;
251 DynBuf printb;
252
253 id = getTracepointId("irq/softirq_exit", &printb);
254 if (id >= 0) {
255 mCounters = new PerfCounter(mCounters, "Linux_irq_softirq", PERF_TYPE_TRACEPOINT, id, true);
256 }
257
258 id = getTracepointId("irq/irq_handler_exit", &printb);
259 if (id >= 0) {
260 mCounters = new PerfCounter(mCounters, "Linux_irq_irq", PERF_TYPE_TRACEPOINT, id, true);
261 }
262
263 //Linux_block_rq_wr
264 //Linux_block_rq_rd
265 //Linux_net_rx
266 //Linux_net_tx
267
268 id = getTracepointId(SCHED_SWITCH, &printb);
269 if (id >= 0) {
270 mCounters = new PerfCounter(mCounters, "Linux_sched_switch", PERF_TYPE_TRACEPOINT, id, true);
271 }
272
273 //Linux_meminfo_memused
274 //Linux_meminfo_memfree
275 //Linux_meminfo_bufferram
276 //Linux_power_cpu_freq
277 //Linux_power_cpu_idle
278
279 mCounters = new PerfCounter(mCounters, "Linux_cpu_wait_contention", TYPE_DERIVED, -1, false);
280
281 //Linux_cpu_wait_io
282
283 mIsSetup = true;
284 return true;
285}
286
287bool PerfDriver::summary(Buffer *const buffer) {
288 struct utsname utsname;
289 if (uname(&utsname) != 0) {
290 logg->logMessage("%s(%s:%i): uname failed", __FUNCTION__, __FILE__, __LINE__);
291 return false;
292 }
293
294 char buf[512];
295 snprintf(buf, sizeof(buf), "%s %s %s %s %s GNU/Linux", utsname.sysname, utsname.nodename, utsname.release, utsname.version, utsname.machine);
296
297 struct timespec ts;
298 if (clock_gettime(CLOCK_REALTIME, &ts) != 0) {
299 logg->logMessage("%s(%s:%i): clock_gettime failed", __FUNCTION__, __FILE__, __LINE__);
300 return false;
301 }
302 const int64_t timestamp = (int64_t)ts.tv_sec * 1000000000L + ts.tv_nsec;
303
304 const int64_t uptime = getTime();
305
306 buffer->summary(timestamp, uptime, 0, buf);
307
308 for (int i = 0; i < gSessionData->mCores; ++i) {
309 // Don't send information on a cpu we know nothing about
310 if (gSessionData->mCpuIds[i] == -1) {
311 continue;
312 }
313
314 int j;
315 for (j = 0; j < ARRAY_LENGTH(gator_cpus); ++j) {
316 if (gator_cpus[j].cpuid == gSessionData->mCpuIds[i]) {
317 break;
318 }
319 }
320 if (gator_cpus[j].cpuid == gSessionData->mCpuIds[i]) {
321 buffer->coreName(i, gSessionData->mCpuIds[i], gator_cpus[j].core_name);
322 } else {
323 if (gSessionData->mCpuIds[i] == -1) {
324 snprintf(buf, sizeof(buf), "Unknown");
325 } else {
326 snprintf(buf, sizeof(buf), "Unknown (0x%.3x)", gSessionData->mCpuIds[i]);
327 }
328 buffer->coreName(i, gSessionData->mCpuIds[i], buf);
329 }
330 }
331 buffer->commit(1);
332
333 return true;
334}
335
336PerfCounter *PerfDriver::findCounter(const Counter &counter) const {
337 for (PerfCounter * perfCounter = mCounters; perfCounter != NULL; perfCounter = perfCounter->getNext()) {
338 if (strcmp(perfCounter->getName(), counter.getType()) == 0) {
339 return perfCounter;
340 }
341 }
342
343 return NULL;
344}
345
346bool PerfDriver::claimCounter(const Counter &counter) const {
347 return findCounter(counter) != NULL;
348}
349
350void PerfDriver::resetCounters() {
351 for (PerfCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) {
352 counter->setEnabled(false);
353 }
354}
355
356void PerfDriver::setupCounter(Counter &counter) {
357 PerfCounter *const perfCounter = findCounter(counter);
358 if (perfCounter == NULL) {
359 counter.setEnabled(false);
360 return;
361 }
362
363 // Don't use the config from counters XML if it's not set, ex: software counters
364 if (counter.getEvent() != -1) {
365 perfCounter->setConfig(counter.getEvent());
366 }
367 perfCounter->setCount(counter.getCount());
368 perfCounter->setEnabled(true);
369 counter.setKey(perfCounter->getKey());
370}
371
372int PerfDriver::writeCounters(mxml_node_t *root) const {
373 int count = 0;
374 for (PerfCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) {
375 mxml_node_t *node = mxmlNewElement(root, "counter");
376 mxmlElementSetAttr(node, "name", counter->getName());
377 ++count;
378 }
379
380 return count;
381}
382
383bool PerfDriver::enable(PerfGroup *const group, Buffer *const buffer) const {
384 for (PerfCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) {
385 if (counter->isEnabled() && (counter->getType() != TYPE_DERIVED)) {
386 if (!group->add(buffer, counter->getKey(), counter->getType(), counter->getConfig(), counter->getCount(), counter->getCount() > 0 ? PERF_SAMPLE_TID | PERF_SAMPLE_IP : 0, counter->isPerCpu() ? PERF_GROUP_PER_CPU : 0)) {
387 logg->logMessage("%s(%s:%i): PerfGroup::add failed", __FUNCTION__, __FILE__, __LINE__);
388 return false;
389 }
390 }
391 }
392
393 return true;
394}
395
396long long PerfDriver::getTracepointId(const char *const name, DynBuf *const printb) {
397 if (!printb->printf(EVENTS_PATH "/%s/id", name)) {
398 logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
399 return -1;
400 }
401
402 int64_t result;
403 if (DriverSource::readInt64Driver(printb->getBuf(), &result) != 0) {
404 logg->logMessage("%s(%s:%i): DriverSource::readInt64Driver failed", __FUNCTION__, __FILE__, __LINE__);
405 return -1;
406 }
407
408 return result;
409}
diff --git a/tools/gator/daemon/PerfDriver.h b/tools/gator/daemon/PerfDriver.h
new file mode 100644
index 00000000000..2cae575a705
--- /dev/null
+++ b/tools/gator/daemon/PerfDriver.h
@@ -0,0 +1,60 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef PERFDRIVER_H
10#define PERFDRIVER_H
11
12#include "Driver.h"
13
14// If debugfs is not mounted at /sys/kernel/debug, update DEBUGFS_PATH
15#define DEBUGFS_PATH "/sys/kernel/debug"
16#define EVENTS_PATH DEBUGFS_PATH "/tracing/events"
17
18#define SCHED_SWITCH "sched/sched_switch"
19
20class Buffer;
21class DynBuf;
22class PerfCounter;
23class PerfGroup;
24
25class PerfDriver : public Driver {
26public:
27 PerfDriver();
28 ~PerfDriver();
29
30 bool getLegacySupport() const { return mLegacySupport; }
31
32 bool setup();
33 bool summary(Buffer *const buffer);
34 bool isSetup() const { return mIsSetup; }
35
36 bool claimCounter(const Counter &counter) const;
37 void resetCounters();
38 void setupCounter(Counter &counter);
39
40 int writeCounters(mxml_node_t *root) const;
41
42 bool enable(PerfGroup *const group, Buffer *const buffer) const;
43
44 static long long getTracepointId(const char *const name, DynBuf *const printb);
45
46private:
47 PerfCounter *findCounter(const Counter &counter) const;
48 void addCpuCounters(const char *const counterName, const int type, const int numCounters);
49 void addUncoreCounters(const char *const counterName, const int type, const int numCounters);
50
51 PerfCounter *mCounters;
52 bool mIsSetup;
53 bool mLegacySupport;
54
55 // Intentionally undefined
56 PerfDriver(const PerfDriver &);
57 PerfDriver &operator=(const PerfDriver &);
58};
59
60#endif // PERFDRIVER_H
diff --git a/tools/gator/daemon/PerfGroup.cpp b/tools/gator/daemon/PerfGroup.cpp
new file mode 100644
index 00000000000..2a0239f7c34
--- /dev/null
+++ b/tools/gator/daemon/PerfGroup.cpp
@@ -0,0 +1,226 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "PerfGroup.h"
10
11#include <errno.h>
12#include <string.h>
13#include <sys/ioctl.h>
14#include <sys/syscall.h>
15#include <unistd.h>
16
17#include "Buffer.h"
18#include "Logging.h"
19#include "Monitor.h"
20#include "PerfBuffer.h"
21#include "SessionData.h"
22
23#define DEFAULT_PEA_ARGS(pea, additionalSampleType) \
24 pea.size = sizeof(pea); \
25 /* Emit time, read_format below, group leader id, and raw tracepoint info */ \
26 pea.sample_type = (gSessionData->perf.getLegacySupport() \
27 ? PERF_SAMPLE_TID | PERF_SAMPLE_IP | PERF_SAMPLE_TIME | PERF_SAMPLE_READ | PERF_SAMPLE_ID \
28 : PERF_SAMPLE_TIME | PERF_SAMPLE_READ | PERF_SAMPLE_IDENTIFIER ) | additionalSampleType; \
29 /* Emit emit value in group format */ \
30 pea.read_format = PERF_FORMAT_ID | PERF_FORMAT_GROUP; \
31 /* start out disabled */ \
32 pea.disabled = 1; \
33 /* have a sampling interrupt happen when we cross the wakeup_watermark boundary */ \
34 pea.watermark = 1; \
35 /* Be conservative in flush size as only one buffer set is monitored */ \
36 pea.wakeup_watermark = 3 * BUF_SIZE / 4
37
38static int sys_perf_event_open(struct perf_event_attr *const attr, const pid_t pid, const int cpu, const int group_fd, const unsigned long flags) {
39 return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags);
40}
41
42PerfGroup::PerfGroup(PerfBuffer *const pb) : mPb(pb) {
43 memset(&mAttrs, 0, sizeof(mAttrs));
44 memset(&mPerCpu, 0, sizeof(mPerCpu));
45 memset(&mKeys, -1, sizeof(mKeys));
46 memset(&mFds, -1, sizeof(mFds));
47}
48
49PerfGroup::~PerfGroup() {
50 for (int pos = ARRAY_LENGTH(mFds) - 1; pos >= 0; --pos) {
51 if (mFds[pos] >= 0) {
52 close(mFds[pos]);
53 }
54 }
55}
56
57bool PerfGroup::add(Buffer *const buffer, const int key, const __u32 type, const __u64 config, const __u64 sample, const __u64 sampleType, const int flags) {
58 int i;
59 for (i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
60 if (mKeys[i] < 0) {
61 break;
62 }
63 }
64
65 if (i >= ARRAY_LENGTH(mKeys)) {
66 logg->logMessage("%s(%s:%i): Too many counters", __FUNCTION__, __FILE__, __LINE__);
67 return false;
68 }
69
70 DEFAULT_PEA_ARGS(mAttrs[i], sampleType);
71 mAttrs[i].type = type;
72 mAttrs[i].config = config;
73 mAttrs[i].sample_period = sample;
74 // always be on the CPU but only a group leader can be pinned
75 mAttrs[i].pinned = (i == 0 ? 1 : 0);
76 mAttrs[i].mmap = (flags & PERF_GROUP_MMAP ? 1 : 0);
77 mAttrs[i].comm = (flags & PERF_GROUP_COMM ? 1 : 0);
78 mAttrs[i].freq = (flags & PERF_GROUP_FREQ ? 1 : 0);
79 mAttrs[i].task = (flags & PERF_GROUP_TASK ? 1 : 0);
80 mAttrs[i].sample_id_all = (flags & PERF_GROUP_SAMPLE_ID_ALL ? 1 : 0);
81 mPerCpu[i] = (flags & PERF_GROUP_PER_CPU);
82
83 mKeys[i] = key;
84
85 buffer->pea(&mAttrs[i], key);
86
87 return true;
88}
89
90bool PerfGroup::prepareCPU(const int cpu) {
91 logg->logMessage("%s(%s:%i): Onlining cpu %i", __FUNCTION__, __FILE__, __LINE__, cpu);
92
93 for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
94 if (mKeys[i] < 0) {
95 continue;
96 }
97
98 if ((cpu != 0) && !mPerCpu[i]) {
99 continue;
100 }
101
102 const int offset = i * gSessionData->mCores;
103 if (mFds[cpu + offset] >= 0) {
104 logg->logMessage("%s(%s:%i): cpu already online or not correctly cleaned up", __FUNCTION__, __FILE__, __LINE__);
105 return false;
106 }
107
108 logg->logMessage("%s(%s:%i): perf_event_open cpu: %i type: %lli config: %lli sample: %lli sample_type: 0x%llx pinned: %i mmap: %i comm: %i freq: %i task: %i sample_id_all: %i", __FUNCTION__, __FILE__, __LINE__, cpu, (long long)mAttrs[i].type, (long long)mAttrs[i].config, (long long)mAttrs[i].sample_period, (long long)mAttrs[i].sample_type, mAttrs[i].pinned, mAttrs[i].mmap, mAttrs[i].comm, mAttrs[i].freq, mAttrs[i].task, mAttrs[i].sample_id_all);
109 mFds[cpu + offset] = sys_perf_event_open(&mAttrs[i], -1, cpu, i == 0 ? -1 : mFds[cpu], i == 0 ? 0 : PERF_FLAG_FD_OUTPUT);
110 if (mFds[cpu + offset] < 0) {
111 logg->logMessage("%s(%s:%i): failed %s", __FUNCTION__, __FILE__, __LINE__, strerror(errno));
112 continue;
113 }
114
115 if (!mPb->useFd(cpu, mFds[cpu + offset], mFds[cpu])) {
116 logg->logMessage("%s(%s:%i): PerfBuffer::useFd failed", __FUNCTION__, __FILE__, __LINE__);
117 return false;
118 }
119 }
120
121 return true;
122}
123
124int PerfGroup::onlineCPU(const int cpu, const bool start, Buffer *const buffer, Monitor *const monitor) {
125 __u64 ids[ARRAY_LENGTH(mKeys)];
126 int coreKeys[ARRAY_LENGTH(mKeys)];
127 int idCount = 0;
128
129 for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
130 const int fd = mFds[cpu + i * gSessionData->mCores];
131 if (fd < 0) {
132 continue;
133 }
134
135 coreKeys[idCount] = mKeys[i];
136 if (!gSessionData->perf.getLegacySupport() && ioctl(fd, PERF_EVENT_IOC_ID, &ids[idCount]) != 0 &&
137 // Workaround for running 32-bit gatord on 64-bit systems, kernel patch in the works
138 ioctl(fd, (PERF_EVENT_IOC_ID & ~IOCSIZE_MASK) | (8 << _IOC_SIZESHIFT), &ids[idCount]) != 0) {
139 logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
140 return false;
141 }
142 ++idCount;
143 }
144
145 if (!monitor->add(mFds[cpu])) {
146 logg->logMessage("%s(%s:%i): Monitor::add failed", __FUNCTION__, __FILE__, __LINE__);
147 return false;
148 }
149
150 if (!gSessionData->perf.getLegacySupport()) {
151 buffer->keys(idCount, ids, coreKeys);
152 } else {
153 char buf[1024];
154 ssize_t bytes = read(mFds[cpu], buf, sizeof(buf));
155 if (bytes < 0) {
156 logg->logMessage("read failed");
157 return false;
158 }
159 buffer->keysOld(idCount, coreKeys, bytes, buf);
160 }
161
162 if (start) {
163 for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
164 int offset = i * gSessionData->mCores + cpu;
165 if (mFds[offset] >= 0 && ioctl(mFds[offset], PERF_EVENT_IOC_ENABLE) < 0) {
166 logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
167 return false;
168 }
169 }
170 }
171
172 return idCount;
173}
174
175bool PerfGroup::offlineCPU(const int cpu) {
176 logg->logMessage("%s(%s:%i): Offlining cpu %i", __FUNCTION__, __FILE__, __LINE__, cpu);
177
178 for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
179 int offset = i * gSessionData->mCores + cpu;
180 if (mFds[offset] >= 0 && ioctl(mFds[offset], PERF_EVENT_IOC_DISABLE) < 0) {
181 logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
182 return false;
183 }
184 }
185
186 // Mark the buffer so that it will be released next time it's read
187 mPb->discard(cpu);
188
189 for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
190 if (mKeys[i] < 0) {
191 continue;
192 }
193
194 int offset = i * gSessionData->mCores + cpu;
195 if (mFds[offset] >= 0) {
196 close(mFds[offset]);
197 mFds[offset] = -1;
198 }
199 }
200
201 return true;
202}
203
204bool PerfGroup::start() {
205 for (int pos = 0; pos < ARRAY_LENGTH(mFds); ++pos) {
206 if (mFds[pos] >= 0 && ioctl(mFds[pos], PERF_EVENT_IOC_ENABLE) < 0) {
207 logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
208 goto fail;
209 }
210 }
211
212 return true;
213
214 fail:
215 stop();
216
217 return false;
218}
219
220void PerfGroup::stop() {
221 for (int pos = ARRAY_LENGTH(mFds) - 1; pos >= 0; --pos) {
222 if (mFds[pos] >= 0) {
223 ioctl(mFds[pos], PERF_EVENT_IOC_DISABLE);
224 }
225 }
226}
diff --git a/tools/gator/daemon/PerfGroup.h b/tools/gator/daemon/PerfGroup.h
new file mode 100644
index 00000000000..3f1e2bb4d1c
--- /dev/null
+++ b/tools/gator/daemon/PerfGroup.h
@@ -0,0 +1,57 @@
1 /**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef PERF_GROUP
10#define PERF_GROUP
11
12// Use a snapshot of perf_event.h as it may be more recent than what is on the target and if not newer features won't be supported anyways
13#include "k/perf_event.h"
14
15#include "Config.h"
16
17class Buffer;
18class Monitor;
19class PerfBuffer;
20
21enum PerfGroupFlags {
22 PERF_GROUP_MMAP = 1 << 0,
23 PERF_GROUP_COMM = 1 << 1,
24 PERF_GROUP_FREQ = 1 << 2,
25 PERF_GROUP_TASK = 1 << 3,
26 PERF_GROUP_SAMPLE_ID_ALL = 1 << 4,
27 PERF_GROUP_PER_CPU = 1 << 5,
28};
29
30class PerfGroup {
31public:
32 PerfGroup(PerfBuffer *const pb);
33 ~PerfGroup();
34
35 bool add(Buffer *const buffer, const int key, const __u32 type, const __u64 config, const __u64 sample, const __u64 sampleType, const int flags);
36 // Safe to call concurrently
37 bool prepareCPU(const int cpu);
38 // Not safe to call concurrently. Returns the number of events enabled
39 int onlineCPU(const int cpu, const bool start, Buffer *const buffer, Monitor *const monitor);
40 bool offlineCPU(int cpu);
41 bool start();
42 void stop();
43
44private:
45 // +1 for the group leader
46 struct perf_event_attr mAttrs[MAX_PERFORMANCE_COUNTERS + 1];
47 bool mPerCpu[MAX_PERFORMANCE_COUNTERS + 1];
48 int mKeys[MAX_PERFORMANCE_COUNTERS + 1];
49 int mFds[NR_CPUS * (MAX_PERFORMANCE_COUNTERS + 1)];
50 PerfBuffer *const mPb;
51
52 // Intentionally undefined
53 PerfGroup(const PerfGroup &);
54 PerfGroup &operator=(const PerfGroup &);
55};
56
57#endif // PERF_GROUP
diff --git a/tools/gator/daemon/PerfSource.cpp b/tools/gator/daemon/PerfSource.cpp
new file mode 100644
index 00000000000..ecfaa66832b
--- /dev/null
+++ b/tools/gator/daemon/PerfSource.cpp
@@ -0,0 +1,275 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "PerfSource.h"
10
11#include <errno.h>
12#include <string.h>
13#include <unistd.h>
14
15#include "Child.h"
16#include "DynBuf.h"
17#include "Logging.h"
18#include "PerfDriver.h"
19#include "Proc.h"
20#include "SessionData.h"
21
22#define MS_PER_US 1000000
23
24extern Child *child;
25
26static bool sendTracepointFormat(Buffer *const buffer, const char *const name, DynBuf *const printb, DynBuf *const b) {
27 if (!printb->printf(EVENTS_PATH "/%s/format", name)) {
28 logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
29 return false;
30 }
31 if (!b->read(printb->getBuf())) {
32 logg->logMessage("%s(%s:%i): DynBuf::read failed", __FUNCTION__, __FILE__, __LINE__);
33 return false;
34 }
35 buffer->format(b->getLength(), b->getBuf());
36
37 return true;
38}
39
40PerfSource::PerfSource(sem_t *senderSem, sem_t *startProfile) : mSummary(0, FRAME_SUMMARY, 1024, senderSem), mBuffer(0, FRAME_PERF_ATTRS, 4*1024*1024, senderSem), mCountersBuf(), mCountersGroup(&mCountersBuf), mMonitor(), mUEvent(), mSenderSem(senderSem), mStartProfile(startProfile), mInterruptFd(-1), mIsDone(false) {
41 long l = sysconf(_SC_PAGE_SIZE);
42 if (l < 0) {
43 logg->logError(__FILE__, __LINE__, "Unable to obtain the page size");
44 handleException();
45 }
46 gSessionData->mPageSize = static_cast<int>(l);
47
48 l = sysconf(_SC_NPROCESSORS_CONF);
49 if (l < 0) {
50 logg->logError(__FILE__, __LINE__, "Unable to obtain the number of cores");
51 handleException();
52 }
53 gSessionData->mCores = static_cast<int>(l);
54}
55
56PerfSource::~PerfSource() {
57}
58
59struct PrepareParallelArgs {
60 PerfGroup *pg;
61 int cpu;
62};
63
64void *prepareParallel(void *arg) {
65 const PrepareParallelArgs *const args = (PrepareParallelArgs *)arg;
66 args->pg->prepareCPU(args->cpu);
67 return NULL;
68}
69
70bool PerfSource::prepare() {
71 DynBuf printb;
72 DynBuf b1;
73 DynBuf b2;
74 DynBuf b3;
75 long long schedSwitchId;
76
77 // Reread cpuinfo since cores may have changed since startup
78 gSessionData->readCpuInfo();
79
80 if (0
81 || !mMonitor.init()
82 || !mUEvent.init()
83 || !mMonitor.add(mUEvent.getFd())
84
85 || (schedSwitchId = PerfDriver::getTracepointId(SCHED_SWITCH, &printb)) < 0
86 || !sendTracepointFormat(&mBuffer, SCHED_SWITCH, &printb, &b1)
87
88 // Only want RAW but not IP on sched_switch and don't want TID on SAMPLE_ID
89 || !mCountersGroup.add(&mBuffer, 100/**/, PERF_TYPE_TRACEPOINT, schedSwitchId, 1, PERF_SAMPLE_RAW, PERF_GROUP_MMAP | PERF_GROUP_COMM | PERF_GROUP_TASK | PERF_GROUP_SAMPLE_ID_ALL | PERF_GROUP_PER_CPU)
90
91 // Only want TID and IP but not RAW on timer
92 || (gSessionData->mSampleRate > 0 && !gSessionData->mIsEBS && !mCountersGroup.add(&mBuffer, 99/**/, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK, 1000000000UL / gSessionData->mSampleRate, PERF_SAMPLE_TID | PERF_SAMPLE_IP, PERF_GROUP_PER_CPU))
93
94 || !gSessionData->perf.enable(&mCountersGroup, &mBuffer)
95 || 0) {
96 logg->logMessage("%s(%s:%i): perf setup failed, are you running Linux 3.4 or later?", __FUNCTION__, __FILE__, __LINE__);
97 return false;
98 }
99
100 if (!gSessionData->perf.summary(&mSummary)) {
101 logg->logMessage("%s(%s:%i): PerfDriver::summary failed", __FUNCTION__, __FILE__, __LINE__);
102 return false;
103 }
104
105 {
106 // Run prepareCPU in parallel as perf_event_open can take more than 1 sec in some cases
107 pthread_t threads[NR_CPUS];
108 PrepareParallelArgs args[NR_CPUS];
109 for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
110 args[cpu].pg = &mCountersGroup;
111 args[cpu].cpu = cpu;
112 if (pthread_create(&threads[cpu], NULL, prepareParallel, &args[cpu]) != 0) {
113 logg->logMessage("%s(%s:%i): pthread_create failed", __FUNCTION__, __FILE__, __LINE__);
114 return false;
115 }
116 }
117 for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
118 if (pthread_join(threads[cpu], NULL) != 0) {
119 logg->logMessage("%s(%s:%i): pthread_join failed", __FUNCTION__, __FILE__, __LINE__);
120 return false;
121 }
122 }
123 }
124
125 int numEvents = 0;
126 for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
127 numEvents += mCountersGroup.onlineCPU(cpu, false, &mBuffer, &mMonitor);
128 }
129 if (numEvents <= 0) {
130 logg->logMessage("%s(%s:%i): PerfGroup::onlineCPU failed on all cores", __FUNCTION__, __FILE__, __LINE__);
131 return false;
132 }
133
134 // Start events before reading proc to avoid race conditions
135 if (!mCountersGroup.start()) {
136 logg->logMessage("%s(%s:%i): PerfGroup::start failed", __FUNCTION__, __FILE__, __LINE__);
137 return false;
138 }
139
140 if (!readProc(&mBuffer, true, &printb, &b1, &b2, &b3)) {
141 logg->logMessage("%s(%s:%i): readProc failed", __FUNCTION__, __FILE__, __LINE__);
142 return false;
143 }
144
145 mBuffer.commit(1);
146
147 return true;
148}
149
150static const char CPU_DEVPATH[] = "/devices/system/cpu/cpu";
151
152void PerfSource::run() {
153 int pipefd[2];
154
155 if (pipe(pipefd) != 0) {
156 logg->logError(__FILE__, __LINE__, "pipe failed");
157 handleException();
158 }
159 mInterruptFd = pipefd[1];
160
161 if (!mMonitor.add(pipefd[0])) {
162 logg->logError(__FILE__, __LINE__, "Monitor::add failed");
163 handleException();
164 }
165
166 int timeout = -1;
167 if (gSessionData->mLiveRate > 0) {
168 timeout = gSessionData->mLiveRate/MS_PER_US;
169 }
170
171 sem_post(mStartProfile);
172
173 while (gSessionData->mSessionIsActive) {
174 // +1 for uevents, +1 for pipe
175 struct epoll_event events[NR_CPUS + 2];
176 int ready = mMonitor.wait(events, ARRAY_LENGTH(events), timeout);
177 if (ready < 0) {
178 logg->logError(__FILE__, __LINE__, "Monitor::wait failed");
179 handleException();
180 }
181
182 for (int i = 0; i < ready; ++i) {
183 if (events[i].data.fd == mUEvent.getFd()) {
184 if (!handleUEvent()) {
185 logg->logError(__FILE__, __LINE__, "PerfSource::handleUEvent failed");
186 handleException();
187 }
188 break;
189 }
190 }
191
192 // send a notification that data is ready
193 sem_post(mSenderSem);
194
195 // In one shot mode, stop collection once all the buffers are filled
196 // Assume timeout == 0 in this case
197 if (gSessionData->mOneShot && gSessionData->mSessionIsActive) {
198 logg->logMessage("%s(%s:%i): One shot", __FUNCTION__, __FILE__, __LINE__);
199 child->endSession();
200 }
201 }
202
203 mCountersGroup.stop();
204 mBuffer.setDone();
205 mIsDone = true;
206
207 // send a notification that data is ready
208 sem_post(mSenderSem);
209
210 mInterruptFd = -1;
211 close(pipefd[0]);
212 close(pipefd[1]);
213}
214
215bool PerfSource::handleUEvent() {
216 UEventResult result;
217 if (!mUEvent.read(&result)) {
218 logg->logMessage("%s(%s:%i): UEvent::Read failed", __FUNCTION__, __FILE__, __LINE__);
219 return false;
220 }
221
222 if (strcmp(result.mSubsystem, "cpu") == 0) {
223 if (strncmp(result.mDevPath, CPU_DEVPATH, sizeof(CPU_DEVPATH) - 1) != 0) {
224 logg->logMessage("%s(%s:%i): Unexpected cpu DEVPATH format", __FUNCTION__, __FILE__, __LINE__);
225 return false;
226 }
227 char *endptr;
228 errno = 0;
229 int cpu = strtol(result.mDevPath + sizeof(CPU_DEVPATH) - 1, &endptr, 10);
230 if (errno != 0 || *endptr != '\0') {
231 logg->logMessage("%s(%s:%i): strtol failed", __FUNCTION__, __FILE__, __LINE__);
232 return false;
233 }
234 if (strcmp(result.mAction, "online") == 0) {
235 // Only call onlineCPU if prepareCPU succeeded
236 const bool result = mCountersGroup.prepareCPU(cpu) &&
237 mCountersGroup.onlineCPU(cpu, true, &mBuffer, &mMonitor);
238 mBuffer.commit(1);
239 return result;
240 } else if (strcmp(result.mAction, "offline") == 0) {
241 return mCountersGroup.offlineCPU(cpu);
242 }
243 }
244
245 return true;
246}
247
248void PerfSource::interrupt() {
249 if (mInterruptFd >= 0) {
250 int8_t c = 0;
251 // Write to the pipe to wake the monitor which will cause mSessionIsActive to be reread
252 if (::write(mInterruptFd, &c, sizeof(c)) != sizeof(c)) {
253 logg->logError(__FILE__, __LINE__, "write failed");
254 handleException();
255 }
256 }
257}
258
259bool PerfSource::isDone () {
260 return mBuffer.isDone() && mIsDone && mCountersBuf.isEmpty();
261}
262
263void PerfSource::write (Sender *sender) {
264 if (!mSummary.isDone()) {
265 mSummary.write(sender);
266 gSessionData->mSentSummary = true;
267 }
268 if (!mBuffer.isDone()) {
269 mBuffer.write(sender);
270 }
271 if (!mCountersBuf.send(sender)) {
272 logg->logError(__FILE__, __LINE__, "PerfBuffer::send failed");
273 handleException();
274 }
275}
diff --git a/tools/gator/daemon/PerfSource.h b/tools/gator/daemon/PerfSource.h
new file mode 100644
index 00000000000..3f471c8de41
--- /dev/null
+++ b/tools/gator/daemon/PerfSource.h
@@ -0,0 +1,54 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef PERFSOURCE_H
10#define PERFSOURCE_H
11
12#include <semaphore.h>
13
14#include "Buffer.h"
15#include "Monitor.h"
16#include "PerfBuffer.h"
17#include "PerfGroup.h"
18#include "Source.h"
19#include "UEvent.h"
20
21class Sender;
22
23class PerfSource : public Source {
24public:
25 PerfSource(sem_t *senderSem, sem_t *startProfile);
26 ~PerfSource();
27
28 bool prepare();
29 void run();
30 void interrupt();
31
32 bool isDone();
33 void write(Sender *sender);
34
35private:
36 bool handleUEvent();
37
38 Buffer mSummary;
39 Buffer mBuffer;
40 PerfBuffer mCountersBuf;
41 PerfGroup mCountersGroup;
42 Monitor mMonitor;
43 UEvent mUEvent;
44 sem_t *const mSenderSem;
45 sem_t *const mStartProfile;
46 int mInterruptFd;
47 bool mIsDone;
48
49 // Intentionally undefined
50 PerfSource(const PerfSource &);
51 PerfSource &operator=(const PerfSource &);
52};
53
54#endif // PERFSOURCE_H
diff --git a/tools/gator/daemon/Proc.cpp b/tools/gator/daemon/Proc.cpp
new file mode 100644
index 00000000000..9f01770d660
--- /dev/null
+++ b/tools/gator/daemon/Proc.cpp
@@ -0,0 +1,215 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "Proc.h"
10
11#include <dirent.h>
12#include <errno.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16
17#include "Buffer.h"
18#include "DynBuf.h"
19#include "Logging.h"
20
21struct ProcStat {
22 // From linux-dev/include/linux/sched.h
23#define TASK_COMM_LEN 16
24 // TASK_COMM_LEN may grow, so be ready for it to get larger
25 char comm[2*TASK_COMM_LEN];
26 long numThreads;
27};
28
29static bool readProcStat(ProcStat *const ps, const char *const pathname, DynBuf *const b) {
30 if (!b->read(pathname)) {
31 logg->logMessage("%s(%s:%i): DynBuf::read failed, likely because the thread exited", __FUNCTION__, __FILE__, __LINE__);
32 // This is not a fatal error - the thread just doesn't exist any more
33 return true;
34 }
35
36 char *comm = strchr(b->getBuf(), '(');
37 if (comm == NULL) {
38 logg->logMessage("%s(%s:%i): parsing stat failed", __FUNCTION__, __FILE__, __LINE__);
39 return false;
40 }
41 ++comm;
42 char *const str = strrchr(comm, ')');
43 if (str == NULL) {
44 logg->logMessage("%s(%s:%i): parsing stat failed", __FUNCTION__, __FILE__, __LINE__);
45 return false;
46 }
47 *str = '\0';
48 strncpy(ps->comm, comm, sizeof(ps->comm) - 1);
49 ps->comm[sizeof(ps->comm) - 1] = '\0';
50
51 const int count = sscanf(str + 2, " %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %ld", &ps->numThreads);
52 if (count != 1) {
53 logg->logMessage("%s(%s:%i): sscanf failed", __FUNCTION__, __FILE__, __LINE__);
54 return false;
55 }
56
57 return true;
58}
59
60static const char *readProcExe(DynBuf *const printb, const int pid, const int tid, DynBuf *const b) {
61 if (tid == -1 ? !printb->printf("/proc/%i/exe", pid)
62 : !printb->printf("/proc/%i/task/%i/exe", pid, tid)) {
63 logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
64 return NULL;
65 }
66
67 const int err = b->readlink(printb->getBuf());
68 const char *image;
69 if (err == 0) {
70 image = strrchr(b->getBuf(), '/');
71 if (image == NULL) {
72 image = b->getBuf();
73 } else {
74 ++image;
75 }
76 } else if (err == -ENOENT) {
77 // readlink /proc/[pid]/exe returns ENOENT for kernel threads
78 image = "\0";
79 } else {
80 logg->logMessage("%s(%s:%i): DynBuf::readlink failed", __FUNCTION__, __FILE__, __LINE__);
81 return NULL;
82 }
83
84 // Android apps are run by app_process but the cmdline is changed to reference the actual app name
85 if (strcmp(image, "app_process") != 0) {
86 return image;
87 }
88
89 if (tid == -1 ? !printb->printf("/proc/%i/cmdline", pid)
90 : !printb->printf("/proc/%i/task/%i/cmdline", pid, tid)) {
91 logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
92 return NULL;
93 }
94
95 if (!b->read(printb->getBuf())) {
96 logg->logMessage("%s(%s:%i): DynBuf::read failed, likely because the thread exited", __FUNCTION__, __FILE__, __LINE__);
97 return NULL;
98 }
99
100 return b->getBuf();
101}
102
103static bool readProcTask(Buffer *const buffer, const int pid, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2) {
104 bool result = false;
105
106 if (!b1->printf("/proc/%i/task", pid)) {
107 logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
108 return result;
109 }
110 DIR *task = opendir(b1->getBuf());
111 if (task == NULL) {
112 logg->logMessage("%s(%s:%i): opendir failed", __FUNCTION__, __FILE__, __LINE__);
113 return result;
114 }
115
116 struct dirent *dirent;
117 while ((dirent = readdir(task)) != NULL) {
118 char *endptr;
119 const int tid = strtol(dirent->d_name, &endptr, 10);
120 if (*endptr != '\0') {
121 // Ignore task items that are not integers like ., etc...
122 continue;
123 }
124
125 if (!printb->printf("/proc/%i/task/%i/stat", pid, tid)) {
126 logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
127 goto fail;
128 }
129 ProcStat ps;
130 if (!readProcStat(&ps, printb->getBuf(), b1)) {
131 logg->logMessage("%s(%s:%i): readProcStat failed", __FUNCTION__, __FILE__, __LINE__);
132 goto fail;
133 }
134
135 const char *const image = readProcExe(printb, pid, tid, b2);
136 if (image == NULL) {
137 logg->logMessage("%s(%s:%i): readImage failed", __FUNCTION__, __FILE__, __LINE__);
138 goto fail;
139 }
140
141 buffer->comm(pid, tid, image, ps.comm);
142 }
143
144 result = true;
145
146 fail:
147 closedir(task);
148
149 return result;
150}
151
152bool readProc(Buffer *const buffer, bool sendMaps, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2, DynBuf *const b3) {
153 bool result = false;
154
155 DIR *proc = opendir("/proc");
156 if (proc == NULL) {
157 logg->logMessage("%s(%s:%i): opendir failed", __FUNCTION__, __FILE__, __LINE__);
158 return result;
159 }
160
161 struct dirent *dirent;
162 while ((dirent = readdir(proc)) != NULL) {
163 char *endptr;
164 const int pid = strtol(dirent->d_name, &endptr, 10);
165 if (*endptr != '\0') {
166 // Ignore proc items that are not integers like ., cpuinfo, etc...
167 continue;
168 }
169
170 if (!printb->printf("/proc/%i/stat", pid)) {
171 logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
172 goto fail;
173 }
174 ProcStat ps;
175 if (!readProcStat(&ps, printb->getBuf(), b1)) {
176 logg->logMessage("%s(%s:%i): readProcStat failed", __FUNCTION__, __FILE__, __LINE__);
177 goto fail;
178 }
179
180 if (sendMaps) {
181 if (!printb->printf("/proc/%i/maps", pid)) {
182 logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
183 goto fail;
184 }
185 if (!b2->read(printb->getBuf())) {
186 logg->logMessage("%s(%s:%i): DynBuf::read failed, likely because the process exited", __FUNCTION__, __FILE__, __LINE__);
187 // This is not a fatal error - the process just doesn't exist any more
188 continue;
189 }
190
191 buffer->maps(pid, pid, b2->getBuf());
192 }
193 if (ps.numThreads <= 1) {
194 const char *const image = readProcExe(printb, pid, -1, b1);
195 if (image == NULL) {
196 logg->logMessage("%s(%s:%i): readImage failed", __FUNCTION__, __FILE__, __LINE__);
197 goto fail;
198 }
199
200 buffer->comm(pid, pid, image, ps.comm);
201 } else {
202 if (!readProcTask(buffer, pid, printb, b1, b3)) {
203 logg->logMessage("%s(%s:%i): readProcTask failed", __FUNCTION__, __FILE__, __LINE__);
204 goto fail;
205 }
206 }
207 }
208
209 result = true;
210
211 fail:
212 closedir(proc);
213
214 return result;
215}
diff --git a/tools/gator/daemon/Proc.h b/tools/gator/daemon/Proc.h
new file mode 100644
index 00000000000..31c2eecb7ae
--- /dev/null
+++ b/tools/gator/daemon/Proc.h
@@ -0,0 +1,17 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef PROC_H
10#define PROC_H
11
12class Buffer;
13class DynBuf;
14
15bool readProc(Buffer *const buffer, bool sendMaps, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2, DynBuf *const b3);
16
17#endif // PROC_H
diff --git a/tools/gator/daemon/Sender.cpp b/tools/gator/daemon/Sender.cpp
new file mode 100644
index 00000000000..3a981a6427b
--- /dev/null
+++ b/tools/gator/daemon/Sender.cpp
@@ -0,0 +1,134 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "Sender.h"
10
11#include <stdlib.h>
12#include <string.h>
13#include <unistd.h>
14
15#include "Buffer.h"
16#include "Logging.h"
17#include "OlySocket.h"
18#include "SessionData.h"
19
20Sender::Sender(OlySocket* socket) {
21 mDataFile = NULL;
22 mDataSocket = NULL;
23
24 // Set up the socket connection
25 if (socket) {
26 char streamline[64] = {0};
27 mDataSocket = socket;
28
29 // Receive magic sequence - can wait forever
30 // Streamline will send data prior to the magic sequence for legacy support, which should be ignored for v4+
31 while (strcmp("STREAMLINE", streamline) != 0) {
32 if (mDataSocket->receiveString(streamline, sizeof(streamline)) == -1) {
33 logg->logError(__FILE__, __LINE__, "Socket disconnected");
34 handleException();
35 }
36 }
37
38 // Send magic sequence - must be done first, after which error messages can be sent
39 char magic[32];
40 snprintf(magic, 32, "GATOR %i\n", PROTOCOL_VERSION);
41 mDataSocket->send(magic, strlen(magic));
42
43 gSessionData->mWaitingOnCommand = true;
44 logg->logMessage("Completed magic sequence");
45 }
46
47 pthread_mutex_init(&mSendMutex, NULL);
48}
49
50Sender::~Sender() {
51 // Just close it as the client socket is on the stack
52 if (mDataSocket != NULL) {
53 mDataSocket->closeSocket();
54 mDataSocket = NULL;
55 }
56 if (mDataFile != NULL) {
57 fclose(mDataFile);
58 }
59}
60
61void Sender::createDataFile(char* apcDir) {
62 if (apcDir == NULL) {
63 return;
64 }
65
66 mDataFileName = (char*)malloc(strlen(apcDir) + 12);
67 sprintf(mDataFileName, "%s/0000000000", apcDir);
68 mDataFile = fopen(mDataFileName, "wb");
69 if (!mDataFile) {
70 logg->logError(__FILE__, __LINE__, "Failed to open binary file: %s", mDataFileName);
71 handleException();
72 }
73}
74
75template<typename T>
76inline T min(const T a, const T b) {
77 return (a < b ? a : b);
78}
79
80void Sender::writeData(const char* data, int length, int type) {
81 if (length < 0 || (data == NULL && length > 0)) {
82 return;
83 }
84
85 // Multiple threads call writeData()
86 pthread_mutex_lock(&mSendMutex);
87
88 // Send data over the socket connection
89 if (mDataSocket) {
90 // Start alarm
91 const int alarmDuration = 8;
92 alarm(alarmDuration);
93
94 // Send data over the socket, sending the type and size first
95 logg->logMessage("Sending data with length %d", length);
96 if (type != RESPONSE_APC_DATA) {
97 // type and length already added by the Collector for apc data
98 unsigned char header[5];
99 header[0] = type;
100 Buffer::writeLEInt(header + 1, length);
101 mDataSocket->send((char*)&header, sizeof(header));
102 }
103
104 // 100Kbits/sec * alarmDuration sec / 8 bits/byte
105 const int chunkSize = 100*1000 * alarmDuration / 8;
106 int pos = 0;
107 while (true) {
108 mDataSocket->send((const char*)data + pos, min(length - pos, chunkSize));
109 pos += chunkSize;
110 if (pos >= length) {
111 break;
112 }
113
114 // Reset the alarm
115 alarm(alarmDuration);
116 logg->logMessage("Resetting the alarm");
117 }
118
119 // Stop alarm
120 alarm(0);
121 }
122
123 // Write data to disk as long as it is not meta data
124 if (mDataFile && type == RESPONSE_APC_DATA) {
125 logg->logMessage("Writing data with length %d", length);
126 // Send data to the data file
127 if (fwrite(data, 1, length, mDataFile) != (unsigned int)length) {
128 logg->logError(__FILE__, __LINE__, "Failed writing binary file %s", mDataFileName);
129 handleException();
130 }
131 }
132
133 pthread_mutex_unlock(&mSendMutex);
134}
diff --git a/tools/gator/daemon/Sender.h b/tools/gator/daemon/Sender.h
new file mode 100644
index 00000000000..33b6cc3c5d8
--- /dev/null
+++ b/tools/gator/daemon/Sender.h
@@ -0,0 +1,42 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef __SENDER_H__
10#define __SENDER_H__
11
12#include <stdio.h>
13#include <pthread.h>
14
15class OlySocket;
16
17enum {
18 RESPONSE_XML = 1,
19 RESPONSE_APC_DATA = 3,
20 RESPONSE_ACK = 4,
21 RESPONSE_NAK = 5,
22 RESPONSE_ERROR = 0xFF
23};
24
25class Sender {
26public:
27 Sender(OlySocket* socket);
28 ~Sender();
29 void writeData(const char* data, int length, int type);
30 void createDataFile(char* apcDir);
31private:
32 OlySocket* mDataSocket;
33 FILE* mDataFile;
34 char* mDataFileName;
35 pthread_mutex_t mSendMutex;
36
37 // Intentionally unimplemented
38 Sender(const Sender &);
39 Sender &operator=(const Sender &);
40};
41
42#endif //__SENDER_H__
diff --git a/tools/gator/daemon/SessionData.cpp b/tools/gator/daemon/SessionData.cpp
new file mode 100644
index 00000000000..14d995fc39f
--- /dev/null
+++ b/tools/gator/daemon/SessionData.cpp
@@ -0,0 +1,194 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "SessionData.h"
10
11#include <string.h>
12#include <sys/mman.h>
13
14#include "SessionXML.h"
15#include "Logging.h"
16
17SessionData* gSessionData = NULL;
18
19SessionData::SessionData() {
20 initialize();
21}
22
23SessionData::~SessionData() {
24}
25
26void SessionData::initialize() {
27 mWaitingOnCommand = false;
28 mSessionIsActive = false;
29 mLocalCapture = false;
30 mOneShot = false;
31 mSentSummary = false;
32 const size_t cpuIdSize = sizeof(int)*NR_CPUS;
33 // Share mCpuIds across all instances of gatord
34 mCpuIds = (int *)mmap(NULL, cpuIdSize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
35 if (mCpuIds == MAP_FAILED) {
36 logg->logError(__FILE__, __LINE__, "Unable to mmap shared memory for cpuids");
37 handleException();
38 }
39 memset(mCpuIds, -1, cpuIdSize);
40 readCpuInfo();
41 mConfigurationXMLPath = NULL;
42 mSessionXMLPath = NULL;
43 mEventsXMLPath = NULL;
44 mTargetPath = NULL;
45 mAPCDir = NULL;
46 mSampleRate = 0;
47 mLiveRate = 0;
48 mDuration = 0;
49 mBacktraceDepth = 0;
50 mTotalBufferSize = 0;
51 // sysconf(_SC_NPROCESSORS_CONF) is unreliable on 2.6 Android, get the value from the kernel module
52 mCores = 1;
53 mPageSize = 0;
54}
55
56void SessionData::parseSessionXML(char* xmlString) {
57 SessionXML session(xmlString);
58 session.parse();
59
60 // Set session data values - use prime numbers just below the desired value to reduce the chance of events firing at the same time
61 if (strcmp(session.parameters.sample_rate, "high") == 0) {
62 mSampleRate = 9973; // 10000
63 } else if (strcmp(session.parameters.sample_rate, "normal") == 0) {
64 mSampleRate = 997; // 1000
65 } else if (strcmp(session.parameters.sample_rate, "low") == 0) {
66 mSampleRate = 97; // 100
67 } else if (strcmp(session.parameters.sample_rate, "none") == 0) {
68 mSampleRate = 0;
69 } else {
70 logg->logError(__FILE__, __LINE__, "Invalid sample rate (%s) in session xml.", session.parameters.sample_rate);
71 handleException();
72 }
73 mBacktraceDepth = session.parameters.call_stack_unwinding == true ? 128 : 0;
74 mDuration = session.parameters.duration;
75
76 // Determine buffer size (in MB) based on buffer mode
77 mOneShot = true;
78 if (strcmp(session.parameters.buffer_mode, "streaming") == 0) {
79 mOneShot = false;
80 mTotalBufferSize = 1;
81 } else if (strcmp(session.parameters.buffer_mode, "small") == 0) {
82 mTotalBufferSize = 1;
83 } else if (strcmp(session.parameters.buffer_mode, "normal") == 0) {
84 mTotalBufferSize = 4;
85 } else if (strcmp(session.parameters.buffer_mode, "large") == 0) {
86 mTotalBufferSize = 16;
87 } else {
88 logg->logError(__FILE__, __LINE__, "Invalid value for buffer mode in session xml.");
89 handleException();
90 }
91
92 mImages = session.parameters.images;
93 // Convert milli- to nanoseconds
94 mLiveRate = session.parameters.live_rate * (int64_t)1000000;
95 if (mLiveRate > 0 && mLocalCapture) {
96 logg->logMessage("Local capture is not compatable with live, disabling live");
97 mLiveRate = 0;
98 }
99}
100
101void SessionData::readCpuInfo() {
102 char temp[256]; // arbitrarily large amount
103 strcpy(mCoreName, "unknown");
104 mMaxCpuId = -1;
105
106 FILE* f = fopen("/proc/cpuinfo", "r");
107 if (f == NULL) {
108 logg->logMessage("Error opening /proc/cpuinfo\n"
109 "The core name in the captured xml file will be 'unknown'.");
110 return;
111 }
112
113 bool foundCoreName = false;
114 int processor = -1;
115 while (fgets(temp, sizeof(temp), f)) {
116 const size_t len = strlen(temp);
117
118 if (len == 1) {
119 // New section, clear the processor. Streamline will not know the cpus if the pre Linux 3.8 format of cpuinfo is encountered but also that no incorrect information will be transmitted.
120 processor = -1;
121 continue;
122 }
123
124 if (len > 0) {
125 temp[len - 1] = '\0'; // Replace the line feed with a null
126 }
127
128 const bool foundHardware = strstr(temp, "Hardware") != 0;
129 const bool foundCPUPart = strstr(temp, "CPU part") != 0;
130 const bool foundProcessor = strstr(temp, "processor") != 0;
131 if (foundHardware || foundCPUPart || foundProcessor) {
132 char* position = strchr(temp, ':');
133 if (position == NULL || (unsigned int)(position - temp) + 2 >= strlen(temp)) {
134 logg->logMessage("Unknown format of /proc/cpuinfo\n"
135 "The core name in the captured xml file will be 'unknown'.");
136 return;
137 }
138 position += 2;
139
140 if (foundHardware) {
141 strncpy(mCoreName, position, sizeof(mCoreName));
142 mCoreName[sizeof(mCoreName) - 1] = 0; // strncpy does not guarantee a null-terminated string
143 foundCoreName = true;
144 }
145
146 if (foundCPUPart) {
147 const int cpuId = strtol(position, NULL, 0);
148 // If this does not have the full topology in /proc/cpuinfo, mCpuIds[0] may not have the 1 CPU part emitted - this guarantees it's in mMaxCpuId
149 if (cpuId > mMaxCpuId) {
150 mMaxCpuId = cpuId;
151 }
152 if (processor >= NR_CPUS) {
153 logg->logMessage("Too many processors, please increase NR_CPUS");
154 } else if (processor >= 0) {
155 mCpuIds[processor] = cpuId;
156 }
157 }
158
159 if (foundProcessor) {
160 processor = strtol(position, NULL, 0);
161 }
162 }
163 }
164
165 if (!foundCoreName) {
166 logg->logMessage("Could not determine core name from /proc/cpuinfo\n"
167 "The core name in the captured xml file will be 'unknown'.");
168 }
169 fclose(f);
170}
171
172uint64_t getTime() {
173 struct timespec ts;
174#ifndef CLOCK_MONOTONIC_RAW
175 // Android doesn't have this defined but it was added in Linux 2.6.28
176#define CLOCK_MONOTONIC_RAW 4
177#endif
178 if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts) != 0) {
179 logg->logError(__FILE__, __LINE__, "Failed to get uptime");
180 handleException();
181 }
182 return (NS_PER_S*ts.tv_sec + ts.tv_nsec);
183}
184
185int getEventKey() {
186 // key 0 is reserved as a timestamp
187 // key 1 is reserved as the marker for thread specific counters
188 // Odd keys are assigned by the driver, even keys by the daemon
189 static int key = 2;
190
191 const int ret = key;
192 key += 2;
193 return ret;
194}
diff --git a/tools/gator/daemon/SessionData.h b/tools/gator/daemon/SessionData.h
new file mode 100644
index 00000000000..835082d86c4
--- /dev/null
+++ b/tools/gator/daemon/SessionData.h
@@ -0,0 +1,86 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef SESSION_DATA_H
10#define SESSION_DATA_H
11
12#include <stdint.h>
13
14#include "Config.h"
15#include "Counter.h"
16#include "FSDriver.h"
17#include "Hwmon.h"
18#include "MaliVideoDriver.h"
19#include "PerfDriver.h"
20
21#define PROTOCOL_VERSION 19
22#define PROTOCOL_DEV 1000 // Differentiates development versions (timestamp) from release versions
23
24#define NS_PER_S ((uint64_t)1000000000)
25
26struct ImageLinkList {
27 char* path;
28 struct ImageLinkList *next;
29};
30
31class SessionData {
32public:
33 static const size_t MAX_STRING_LEN = 80;
34
35 SessionData();
36 ~SessionData();
37 void initialize();
38 void parseSessionXML(char* xmlString);
39 void readCpuInfo();
40
41 Hwmon hwmon;
42 FSDriver fsDriver;
43 PerfDriver perf;
44 MaliVideoDriver maliVideo;
45
46 char mCoreName[MAX_STRING_LEN];
47 struct ImageLinkList *mImages;
48 char* mConfigurationXMLPath;
49 char* mSessionXMLPath;
50 char* mEventsXMLPath;
51 char* mTargetPath;
52 char* mAPCDir;
53
54 bool mWaitingOnCommand;
55 bool mSessionIsActive;
56 bool mLocalCapture;
57 bool mOneShot; // halt processing of the driver data until profiling is complete or the buffer is filled
58 bool mIsEBS;
59 bool mSentSummary;
60
61 int mBacktraceDepth;
62 int mTotalBufferSize; // number of MB to use for the entire collection buffer
63 int mSampleRate;
64 int64_t mLiveRate;
65 int mDuration;
66 int mCores;
67 int mPageSize;
68 int *mCpuIds;
69 int mMaxCpuId;
70
71 // PMU Counters
72 int mCounterOverflow;
73 Counter mCounters[MAX_PERFORMANCE_COUNTERS];
74
75private:
76 // Intentionally unimplemented
77 SessionData(const SessionData &);
78 SessionData &operator=(const SessionData &);
79};
80
81extern SessionData* gSessionData;
82
83uint64_t getTime();
84int getEventKey();
85
86#endif // SESSION_DATA_H
diff --git a/tools/gator/daemon/SessionXML.cpp b/tools/gator/daemon/SessionXML.cpp
new file mode 100644
index 00000000000..8cdc9409ca2
--- /dev/null
+++ b/tools/gator/daemon/SessionXML.cpp
@@ -0,0 +1,111 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "SessionXML.h"
10
11#include <string.h>
12#include <stdlib.h>
13#include <limits.h>
14
15#include "Logging.h"
16#include "OlyUtility.h"
17#include "SessionData.h"
18
19static const char* TAG_SESSION = "session";
20static const char* TAG_IMAGE = "image";
21
22static const char* ATTR_VERSION = "version";
23static const char* ATTR_CALL_STACK_UNWINDING = "call_stack_unwinding";
24static const char* ATTR_BUFFER_MODE = "buffer_mode";
25static const char* ATTR_SAMPLE_RATE = "sample_rate";
26static const char* ATTR_DURATION = "duration";
27static const char* ATTR_PATH = "path";
28static const char* ATTR_LIVE_RATE = "live_rate";
29
30SessionXML::SessionXML(const char *str) {
31 parameters.buffer_mode[0] = 0;
32 parameters.sample_rate[0] = 0;
33 parameters.duration = 0;
34 parameters.call_stack_unwinding = false;
35 parameters.live_rate = 0;
36 parameters.images = NULL;
37 mPath = 0;
38 mSessionXML = (const char *)str;
39 logg->logMessage(mSessionXML);
40}
41
42SessionXML::~SessionXML() {
43 if (mPath != 0) {
44 free((char *)mSessionXML);
45 }
46}
47
48void SessionXML::parse() {
49 mxml_node_t *tree;
50 mxml_node_t *node;
51
52 tree = mxmlLoadString(NULL, mSessionXML, MXML_NO_CALLBACK);
53 node = mxmlFindElement(tree, tree, TAG_SESSION, NULL, NULL, MXML_DESCEND);
54
55 if (node) {
56 sessionTag(tree, node);
57 mxmlDelete(tree);
58 return;
59 }
60
61 logg->logError(__FILE__, __LINE__, "No session tag found in the session.xml file");
62 handleException();
63}
64
65void SessionXML::sessionTag(mxml_node_t *tree, mxml_node_t *node) {
66 int version = 0;
67 if (mxmlElementGetAttr(node, ATTR_VERSION)) version = strtol(mxmlElementGetAttr(node, ATTR_VERSION), NULL, 10);
68 if (version != 1) {
69 logg->logError(__FILE__, __LINE__, "Invalid session.xml version: %d", version);
70 handleException();
71 }
72
73 // copy to pre-allocated strings
74 if (mxmlElementGetAttr(node, ATTR_BUFFER_MODE)) {
75 strncpy(parameters.buffer_mode, mxmlElementGetAttr(node, ATTR_BUFFER_MODE), sizeof(parameters.buffer_mode));
76 parameters.buffer_mode[sizeof(parameters.buffer_mode) - 1] = 0; // strncpy does not guarantee a null-terminated string
77 }
78 if (mxmlElementGetAttr(node, ATTR_SAMPLE_RATE)) {
79 strncpy(parameters.sample_rate, mxmlElementGetAttr(node, ATTR_SAMPLE_RATE), sizeof(parameters.sample_rate));
80 parameters.sample_rate[sizeof(parameters.sample_rate) - 1] = 0; // strncpy does not guarantee a null-terminated string
81 }
82
83 // integers/bools
84 parameters.call_stack_unwinding = util->stringToBool(mxmlElementGetAttr(node, ATTR_CALL_STACK_UNWINDING), false);
85 if (mxmlElementGetAttr(node, ATTR_DURATION)) parameters.duration = strtol(mxmlElementGetAttr(node, ATTR_DURATION), NULL, 10);
86 if (mxmlElementGetAttr(node, ATTR_LIVE_RATE)) parameters.live_rate = strtol(mxmlElementGetAttr(node, ATTR_LIVE_RATE), NULL, 10);
87
88 // parse subtags
89 node = mxmlGetFirstChild(node);
90 while (node) {
91 if (mxmlGetType(node) != MXML_ELEMENT) {
92 node = mxmlWalkNext(node, tree, MXML_NO_DESCEND);
93 continue;
94 }
95 if (strcmp(TAG_IMAGE, mxmlGetElement(node)) == 0) {
96 sessionImage(node);
97 }
98 node = mxmlWalkNext(node, tree, MXML_NO_DESCEND);
99 }
100}
101
102void SessionXML::sessionImage(mxml_node_t *node) {
103 int length = strlen(mxmlElementGetAttr(node, ATTR_PATH));
104 struct ImageLinkList *image;
105
106 image = (struct ImageLinkList *)malloc(sizeof(struct ImageLinkList));
107 image->path = (char*)malloc(length + 1);
108 image->path = strdup(mxmlElementGetAttr(node, ATTR_PATH));
109 image->next = parameters.images;
110 parameters.images = image;
111}
diff --git a/tools/gator/daemon/SessionXML.h b/tools/gator/daemon/SessionXML.h
new file mode 100644
index 00000000000..e146094a4d1
--- /dev/null
+++ b/tools/gator/daemon/SessionXML.h
@@ -0,0 +1,42 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef SESSION_XML_H
10#define SESSION_XML_H
11
12#include "mxml/mxml.h"
13
14struct ImageLinkList;
15
16struct ConfigParameters {
17 char buffer_mode[64]; // buffer mode, "streaming", "low", "normal", "high" defines oneshot and buffer size
18 char sample_rate[64]; // capture mode, "high", "normal", or "low"
19 int duration; // length of profile in seconds
20 bool call_stack_unwinding; // whether stack unwinding is performed
21 int live_rate;
22 struct ImageLinkList *images; // linked list of image strings
23};
24
25class SessionXML {
26public:
27 SessionXML(const char *str);
28 ~SessionXML();
29 void parse();
30 ConfigParameters parameters;
31private:
32 const char *mSessionXML;
33 const char *mPath;
34 void sessionTag(mxml_node_t *tree, mxml_node_t *node);
35 void sessionImage(mxml_node_t *node);
36
37 // Intentionally unimplemented
38 SessionXML(const SessionXML &);
39 SessionXML &operator=(const SessionXML &);
40};
41
42#endif // SESSION_XML_H
diff --git a/tools/gator/daemon/Source.cpp b/tools/gator/daemon/Source.cpp
new file mode 100644
index 00000000000..60cf704e599
--- /dev/null
+++ b/tools/gator/daemon/Source.cpp
@@ -0,0 +1,33 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "Source.h"
10
11#include "Logging.h"
12
13Source::Source() : mThreadID() {
14}
15
16Source::~Source() {
17}
18
19void Source::start() {
20 if (pthread_create(&mThreadID, NULL, runStatic, this)) {
21 logg->logError(__FILE__, __LINE__, "Failed to create source thread");
22 handleException();
23 }
24}
25
26void Source::join() {
27 pthread_join(mThreadID, NULL);
28}
29
30void *Source::runStatic(void *arg) {
31 static_cast<Source *>(arg)->run();
32 return NULL;
33}
diff --git a/tools/gator/daemon/Source.h b/tools/gator/daemon/Source.h
new file mode 100644
index 00000000000..56ac3d6e94f
--- /dev/null
+++ b/tools/gator/daemon/Source.h
@@ -0,0 +1,40 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef SOURCE_H
10#define SOURCE_H
11
12#include <pthread.h>
13
14class Sender;
15
16class Source {
17public:
18 Source();
19 virtual ~Source();
20
21 virtual bool prepare() = 0;
22 void start();
23 virtual void run() = 0;
24 virtual void interrupt() = 0;
25 void join();
26
27 virtual bool isDone() = 0;
28 virtual void write(Sender *sender) = 0;
29
30private:
31 static void *runStatic(void *arg);
32
33 pthread_t mThreadID;
34
35 // Intentionally undefined
36 Source(const Source &);
37 Source &operator=(const Source &);
38};
39
40#endif // SOURCE_H
diff --git a/tools/gator/daemon/StreamlineSetup.cpp b/tools/gator/daemon/StreamlineSetup.cpp
new file mode 100644
index 00000000000..2b61eaeb290
--- /dev/null
+++ b/tools/gator/daemon/StreamlineSetup.cpp
@@ -0,0 +1,272 @@
1/**
2 * Copyright (C) ARM Limited 2011-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "StreamlineSetup.h"
10
11#include "Buffer.h"
12#include "CapturedXML.h"
13#include "ConfigurationXML.h"
14#include "Driver.h"
15#include "EventsXML.h"
16#include "Logging.h"
17#include "OlySocket.h"
18#include "OlyUtility.h"
19#include "Sender.h"
20#include "SessionData.h"
21
22static const char* TAG_SESSION = "session";
23static const char* TAG_REQUEST = "request";
24static const char* TAG_CONFIGURATIONS = "configurations";
25
26static const char* ATTR_TYPE = "type";
27static const char* VALUE_EVENTS = "events";
28static const char* VALUE_CONFIGURATION = "configuration";
29static const char* VALUE_COUNTERS = "counters";
30static const char* VALUE_CAPTURED = "captured";
31static const char* VALUE_DEFAULTS = "defaults";
32
33StreamlineSetup::StreamlineSetup(OlySocket* s) {
34 bool ready = false;
35 char* data = NULL;
36 int type;
37
38 mSocket = s;
39
40 // Receive commands from Streamline (master)
41 while (!ready) {
42 // receive command over socket
43 gSessionData->mWaitingOnCommand = true;
44 data = readCommand(&type);
45
46 // parse and handle data
47 switch (type) {
48 case COMMAND_REQUEST_XML:
49 handleRequest(data);
50 break;
51 case COMMAND_DELIVER_XML:
52 handleDeliver(data);
53 break;
54 case COMMAND_APC_START:
55 logg->logMessage("Received apc start request");
56 ready = true;
57 break;
58 case COMMAND_APC_STOP:
59 logg->logMessage("Received apc stop request before apc start request");
60 exit(0);
61 break;
62 case COMMAND_DISCONNECT:
63 logg->logMessage("Received disconnect command");
64 exit(0);
65 break;
66 case COMMAND_PING:
67 logg->logMessage("Received ping command");
68 sendData(NULL, 0, RESPONSE_ACK);
69 break;
70 default:
71 logg->logError(__FILE__, __LINE__, "Target error: Unknown command type, %d", type);
72 handleException();
73 }
74
75 free(data);
76 }
77
78 if (gSessionData->mCounterOverflow > 0) {
79 logg->logError(__FILE__, __LINE__, "Only %i performance counters are permitted, %i are selected", MAX_PERFORMANCE_COUNTERS, gSessionData->mCounterOverflow);
80 handleException();
81 }
82}
83
84StreamlineSetup::~StreamlineSetup() {
85}
86
87char* StreamlineSetup::readCommand(int* command) {
88 unsigned char header[5];
89 char* data;
90 int response;
91
92 // receive type and length
93 response = mSocket->receiveNBytes((char*)&header, sizeof(header));
94
95 // After receiving a single byte, we are no longer waiting on a command
96 gSessionData->mWaitingOnCommand = false;
97
98 if (response < 0) {
99 logg->logError(__FILE__, __LINE__, "Target error: Unexpected socket disconnect");
100 handleException();
101 }
102
103 const char type = header[0];
104 const int length = (header[1] << 0) | (header[2] << 8) | (header[3] << 16) | (header[4] << 24);
105
106 // add artificial limit
107 if ((length < 0) || length > 1024 * 1024) {
108 logg->logError(__FILE__, __LINE__, "Target error: Invalid length received, %d", length);
109 handleException();
110 }
111
112 // allocate memory to contain the xml file, size of zero returns a zero size object
113 data = (char*)calloc(length + 1, 1);
114 if (data == NULL) {
115 logg->logError(__FILE__, __LINE__, "Unable to allocate memory for xml");
116 handleException();
117 }
118
119 // receive data
120 response = mSocket->receiveNBytes(data, length);
121 if (response < 0) {
122 logg->logError(__FILE__, __LINE__, "Target error: Unexpected socket disconnect");
123 handleException();
124 }
125
126 // null terminate the data for string parsing
127 if (length > 0) {
128 data[length] = 0;
129 }
130
131 *command = type;
132 return data;
133}
134
135void StreamlineSetup::handleRequest(char* xml) {
136 mxml_node_t *tree, *node;
137 const char * attr = NULL;
138
139 tree = mxmlLoadString(NULL, xml, MXML_NO_CALLBACK);
140 node = mxmlFindElement(tree, tree, TAG_REQUEST, ATTR_TYPE, NULL, MXML_DESCEND_FIRST);
141 if (node) {
142 attr = mxmlElementGetAttr(node, ATTR_TYPE);
143 }
144 if (attr && strcmp(attr, VALUE_EVENTS) == 0) {
145 sendEvents();
146 logg->logMessage("Sent events xml response");
147 } else if (attr && strcmp(attr, VALUE_CONFIGURATION) == 0) {
148 sendConfiguration();
149 logg->logMessage("Sent configuration xml response");
150 } else if (attr && strcmp(attr, VALUE_COUNTERS) == 0) {
151 sendCounters();
152 logg->logMessage("Sent counters xml response");
153 } else if (attr && strcmp(attr, VALUE_CAPTURED) == 0) {
154 CapturedXML capturedXML;
155 char* capturedText = capturedXML.getXML(false);
156 sendData(capturedText, strlen(capturedText), RESPONSE_XML);
157 free(capturedText);
158 logg->logMessage("Sent captured xml response");
159 } else if (attr && strcmp(attr, VALUE_DEFAULTS) == 0) {
160 sendDefaults();
161 logg->logMessage("Sent default configuration xml response");
162 } else {
163 char error[] = "Unknown request";
164 sendData(error, strlen(error), RESPONSE_NAK);
165 logg->logMessage("Received unknown request:\n%s", xml);
166 }
167
168 mxmlDelete(tree);
169}
170
171void StreamlineSetup::handleDeliver(char* xml) {
172 mxml_node_t *tree;
173
174 // Determine xml type
175 tree = mxmlLoadString(NULL, xml, MXML_NO_CALLBACK);
176 if (mxmlFindElement(tree, tree, TAG_SESSION, NULL, NULL, MXML_DESCEND_FIRST)) {
177 // Session XML
178 gSessionData->parseSessionXML(xml);
179 sendData(NULL, 0, RESPONSE_ACK);
180 logg->logMessage("Received session xml");
181 } else if (mxmlFindElement(tree, tree, TAG_CONFIGURATIONS, NULL, NULL, MXML_DESCEND_FIRST)) {
182 // Configuration XML
183 writeConfiguration(xml);
184 sendData(NULL, 0, RESPONSE_ACK);
185 logg->logMessage("Received configuration xml");
186 } else {
187 // Unknown XML
188 logg->logMessage("Received unknown XML delivery type");
189 sendData(NULL, 0, RESPONSE_NAK);
190 }
191
192 mxmlDelete(tree);
193}
194
195void StreamlineSetup::sendData(const char* data, uint32_t length, char type) {
196 unsigned char header[5];
197 header[0] = type;
198 Buffer::writeLEInt(header + 1, length);
199 mSocket->send((char*)&header, sizeof(header));
200 mSocket->send((const char*)data, length);
201}
202
203void StreamlineSetup::sendEvents() {
204 EventsXML eventsXML;
205 char* string = eventsXML.getXML();
206 sendString(string, RESPONSE_XML);
207 free(string);
208}
209
210void StreamlineSetup::sendConfiguration() {
211 ConfigurationXML xml;
212
213 const char* string = xml.getConfigurationXML();
214 sendData(string, strlen(string), RESPONSE_XML);
215}
216
217void StreamlineSetup::sendDefaults() {
218 // Send the config built into the binary
219 const char* xml;
220 unsigned int size;
221 ConfigurationXML::getDefaultConfigurationXml(xml, size);
222
223 // Artificial size restriction
224 if (size > 1024*1024) {
225 logg->logError(__FILE__, __LINE__, "Corrupt default configuration file");
226 handleException();
227 }
228
229 sendData(xml, size, RESPONSE_XML);
230}
231
232void StreamlineSetup::sendCounters() {
233 mxml_node_t *xml;
234 mxml_node_t *counters;
235
236 xml = mxmlNewXML("1.0");
237 counters = mxmlNewElement(xml, "counters");
238 int count = 0;
239 for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
240 count += driver->writeCounters(counters);
241 }
242
243 if (count == 0) {
244 logg->logError(__FILE__, __LINE__, "No counters found, this could be because /dev/gator/events can not be read or because perf is not working correctly");
245 handleException();
246 }
247
248 char* string = mxmlSaveAllocString(xml, mxmlWhitespaceCB);
249 sendString(string, RESPONSE_XML);
250
251 free(string);
252 mxmlDelete(xml);
253}
254
255void StreamlineSetup::writeConfiguration(char* xml) {
256 char path[PATH_MAX];
257
258 ConfigurationXML::getPath(path);
259
260 if (util->writeToDisk(path, xml) < 0) {
261 logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify write permissions to this path.", path);
262 handleException();
263 }
264
265 // Re-populate gSessionData with the configuration, as it has now changed
266 { ConfigurationXML configuration; }
267
268 if (gSessionData->mCounterOverflow > 0) {
269 logg->logError(__FILE__, __LINE__, "Only %i performance counters are permitted, %i are selected", MAX_PERFORMANCE_COUNTERS, gSessionData->mCounterOverflow);
270 handleException();
271 }
272}
diff --git a/tools/gator/daemon/StreamlineSetup.h b/tools/gator/daemon/StreamlineSetup.h
new file mode 100644
index 00000000000..b380f46b98f
--- /dev/null
+++ b/tools/gator/daemon/StreamlineSetup.h
@@ -0,0 +1,50 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef __STREAMLINE_SETUP_H__
10#define __STREAMLINE_SETUP_H__
11
12#include <stdint.h>
13#include <string.h>
14
15class OlySocket;
16
17// Commands from Streamline
18enum {
19 COMMAND_REQUEST_XML = 0,
20 COMMAND_DELIVER_XML = 1,
21 COMMAND_APC_START = 2,
22 COMMAND_APC_STOP = 3,
23 COMMAND_DISCONNECT = 4,
24 COMMAND_PING = 5
25};
26
27class StreamlineSetup {
28public:
29 StreamlineSetup(OlySocket *socket);
30 ~StreamlineSetup();
31private:
32 OlySocket* mSocket;
33
34 char* readCommand(int*);
35 void handleRequest(char* xml);
36 void handleDeliver(char* xml);
37 void sendData(const char* data, uint32_t length, char type);
38 void sendString(const char* string, int type) {sendData(string, strlen(string), type);}
39 void sendEvents();
40 void sendConfiguration();
41 void sendDefaults();
42 void sendCounters();
43 void writeConfiguration(char* xml);
44
45 // Intentionally unimplemented
46 StreamlineSetup(const StreamlineSetup &);
47 StreamlineSetup &operator=(const StreamlineSetup &);
48};
49
50#endif //__STREAMLINE_SETUP_H__
diff --git a/tools/gator/daemon/UEvent.cpp b/tools/gator/daemon/UEvent.cpp
new file mode 100644
index 00000000000..54d45751e3c
--- /dev/null
+++ b/tools/gator/daemon/UEvent.cpp
@@ -0,0 +1,76 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "UEvent.h"
10
11#include <string.h>
12#include <sys/socket.h>
13#include <unistd.h>
14
15#include <linux/netlink.h>
16
17#include "Logging.h"
18
19static const char EMPTY[] = "";
20static const char ACTION[] = "ACTION=";
21static const char DEVPATH[] = "DEVPATH=";
22static const char SUBSYSTEM[] = "SUBSYSTEM=";
23
24UEvent::UEvent() : mFd(-1) {
25}
26
27UEvent::~UEvent() {
28 if (mFd >= 0) {
29 close(mFd);
30 }
31}
32
33bool UEvent::init() {
34 mFd = socket(PF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
35 if (mFd < 0) {
36 logg->logMessage("%s(%s:%i): socket failed", __FUNCTION__, __FILE__, __LINE__);
37 return false;
38 }
39
40 struct sockaddr_nl sockaddr;
41 memset(&sockaddr, 0, sizeof(sockaddr));
42 sockaddr.nl_family = AF_NETLINK;
43 sockaddr.nl_groups = 1; // bitmask: (1 << 0) == kernel events, (1 << 1) == udev events
44 sockaddr.nl_pid = 0;
45 if (bind(mFd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) != 0) {
46 logg->logMessage("%s(%s:%i): bind failed", __FUNCTION__, __FILE__, __LINE__);
47 return false;
48 }
49
50 return true;
51}
52
53bool UEvent::read(UEventResult *const result) {
54 ssize_t bytes = recv(mFd, result->mBuf, sizeof(result->mBuf), 0);
55 if (bytes <= 0) {
56 logg->logMessage("%s(%s:%i): recv failed", __FUNCTION__, __FILE__, __LINE__);
57 return false;
58 }
59
60 result->mAction = EMPTY;
61 result->mDevPath = EMPTY;
62 result->mSubsystem = EMPTY;
63
64 for (int pos = 0; pos < bytes; pos += strlen(result->mBuf + pos) + 1) {
65 char *const str = result->mBuf + pos;
66 if (strncmp(str, ACTION, sizeof(ACTION) - 1) == 0) {
67 result->mAction = str + sizeof(ACTION) - 1;
68 } else if (strncmp(str, DEVPATH, sizeof(DEVPATH) - 1) == 0) {
69 result->mDevPath = str + sizeof(DEVPATH) - 1;
70 } else if (strncmp(str, SUBSYSTEM, sizeof(SUBSYSTEM) - 1) == 0) {
71 result->mSubsystem = str + sizeof(SUBSYSTEM) - 1;
72 }
73 }
74
75 return true;
76}
diff --git a/tools/gator/daemon/UEvent.h b/tools/gator/daemon/UEvent.h
new file mode 100644
index 00000000000..2f7ef2c93f5
--- /dev/null
+++ b/tools/gator/daemon/UEvent.h
@@ -0,0 +1,36 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef UEVENT_H
10#define UEVENT_H
11
12struct UEventResult {
13 const char *mAction;
14 const char *mDevPath;
15 const char *mSubsystem;
16 char mBuf[1<<13];
17};
18
19class UEvent {
20public:
21 UEvent();
22 ~UEvent();
23
24 bool init();
25 bool read(UEventResult *const result);
26 int getFd() const { return mFd; }
27
28private:
29 int mFd;
30
31 // Intentionally undefined
32 UEvent(const UEvent &);
33 UEvent &operator=(const UEvent &);
34};
35
36#endif // UEVENT_H
diff --git a/tools/gator/daemon/UserSpaceSource.cpp b/tools/gator/daemon/UserSpaceSource.cpp
new file mode 100644
index 00000000000..8c328e0e0fb
--- /dev/null
+++ b/tools/gator/daemon/UserSpaceSource.cpp
@@ -0,0 +1,89 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "UserSpaceSource.h"
10
11#include <sys/prctl.h>
12#include <unistd.h>
13
14#include "Child.h"
15#include "DriverSource.h"
16#include "Logging.h"
17#include "SessionData.h"
18
19#define NS_PER_US 1000
20
21extern Child *child;
22
23UserSpaceSource::UserSpaceSource(sem_t *senderSem) : mBuffer(0, FRAME_BLOCK_COUNTER, gSessionData->mTotalBufferSize*1024*1024, senderSem) {
24}
25
26UserSpaceSource::~UserSpaceSource() {
27}
28
29bool UserSpaceSource::prepare() {
30 return true;
31}
32
33void UserSpaceSource::run() {
34 prctl(PR_SET_NAME, (unsigned long)&"gatord-counters", 0, 0, 0);
35
36 gSessionData->hwmon.start();
37 gSessionData->fsDriver.start();
38
39 int64_t monotonic_started = 0;
40 while (monotonic_started <= 0) {
41 usleep(10);
42
43 if (DriverSource::readInt64Driver("/dev/gator/started", &monotonic_started) == -1) {
44 logg->logError(__FILE__, __LINE__, "Error reading gator driver start time");
45 handleException();
46 }
47 }
48
49 uint64_t next_time = 0;
50 while (gSessionData->mSessionIsActive) {
51 const uint64_t curr_time = getTime() - monotonic_started;
52 // Sample ten times a second ignoring gSessionData->mSampleRate
53 next_time += NS_PER_S/10;//gSessionData->mSampleRate;
54 if (next_time < curr_time) {
55 logg->logMessage("Too slow, curr_time: %lli next_time: %lli", curr_time, next_time);
56 next_time = curr_time;
57 }
58
59 if (mBuffer.eventHeader(curr_time)) {
60 gSessionData->hwmon.read(&mBuffer);
61 gSessionData->fsDriver.read(&mBuffer);
62 // Only check after writing all counters so that time and corresponding counters appear in the same frame
63 mBuffer.check(curr_time);
64 }
65
66 if (mBuffer.bytesAvailable() <= 0) {
67 logg->logMessage("One shot (counters)");
68 child->endSession();
69 }
70
71 usleep((next_time - curr_time)/NS_PER_US);
72 }
73
74 mBuffer.setDone();
75}
76
77void UserSpaceSource::interrupt() {
78 // Do nothing
79}
80
81bool UserSpaceSource::isDone() {
82 return mBuffer.isDone();
83}
84
85void UserSpaceSource::write(Sender *sender) {
86 if (!mBuffer.isDone()) {
87 mBuffer.write(sender);
88 }
89}
diff --git a/tools/gator/daemon/UserSpaceSource.h b/tools/gator/daemon/UserSpaceSource.h
new file mode 100644
index 00000000000..9b3666016dc
--- /dev/null
+++ b/tools/gator/daemon/UserSpaceSource.h
@@ -0,0 +1,38 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef USERSPACESOURCE_H
10#define USERSPACESOURCE_H
11
12#include <semaphore.h>
13
14#include "Buffer.h"
15#include "Source.h"
16
17// User space counters
18class UserSpaceSource : public Source {
19public:
20 UserSpaceSource(sem_t *senderSem);
21 ~UserSpaceSource();
22
23 bool prepare();
24 void run();
25 void interrupt();
26
27 bool isDone();
28 void write(Sender *sender);
29
30private:
31 Buffer mBuffer;
32
33 // Intentionally unimplemented
34 UserSpaceSource(const UserSpaceSource &);
35 UserSpaceSource &operator=(const UserSpaceSource &);
36};
37
38#endif // USERSPACESOURCE_H
diff --git a/tools/gator/daemon/c++.cpp b/tools/gator/daemon/c++.cpp
new file mode 100644
index 00000000000..6041e5e9646
--- /dev/null
+++ b/tools/gator/daemon/c++.cpp
@@ -0,0 +1,40 @@
1/**
2 * Minimal set of C++ functions so that libstdc++ is not required
3 *
4 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <stdio.h>
12#include <stdlib.h>
13
14void operator delete(void *ptr) {
15 if (ptr != NULL) {
16 free(ptr);
17 }
18}
19
20void operator delete[](void *ptr) {
21 operator delete(ptr);
22}
23
24void *operator new(size_t size) {
25 void *ptr = malloc(size == 0 ? 1 : size);
26 if (ptr == NULL) {
27 abort();
28 }
29 return ptr;
30}
31
32void *operator new[](size_t size) {
33 return operator new(size);
34}
35
36extern "C"
37void __cxa_pure_virtual() {
38 printf("pure virtual method called\n");
39 abort();
40}
diff --git a/tools/gator/daemon/common.mk b/tools/gator/daemon/common.mk
new file mode 100644
index 00000000000..769a92e51a3
--- /dev/null
+++ b/tools/gator/daemon/common.mk
@@ -0,0 +1,52 @@
1# -g produces debugging information
2# -O3 maximum optimization
3# -O0 no optimization, used for debugging
4# -Wall enables most warnings
5# -Werror treats warnings as errors
6# -std=c++0x is the planned new c++ standard
7# -std=c++98 is the 1998 c++ standard
8CPPFLAGS += -O3 -Wall -fno-exceptions -pthread -MMD -DETCDIR=\"/etc\" -Ilibsensors
9CXXFLAGS += -fno-rtti -Wextra # -Weffc++
10ifeq ($(WERROR),1)
11 CPPFLAGS += -Werror
12endif
13# -s strips the binary of debug info
14LDFLAGS += -s
15LDLIBS += -lrt -lm -pthread
16TARGET = gatord
17C_SRC = $(wildcard mxml/*.c) $(wildcard libsensors/*.c)
18CXX_SRC = $(wildcard *.cpp)
19
20all: $(TARGET)
21
22events.xml: events_header.xml $(wildcard events-*.xml) events_footer.xml
23 cat $^ > $@
24
25include $(wildcard *.d)
26include $(wildcard mxml/*.d)
27
28EventsXML.cpp: events_xml.h
29ConfigurationXML.cpp: defaults_xml.h
30
31# Don't regenerate conf-lex.c or conf-parse.c
32libsensors/conf-lex.c: ;
33libsensors/conf-parse.c: ;
34
35%_xml.h: %.xml escape
36 ./escape $< > $@
37
38%.o: %.c
39 $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
40
41%.o: %.cpp
42 $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
43
44$(TARGET): $(CXX_SRC:%.cpp=%.o) $(C_SRC:%.c=%.o)
45 $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
46
47# Intentionally ignore CC as a native binary is required
48escape: escape.c
49 gcc $^ -o $@
50
51clean:
52 rm -f *.d *.o mxml/*.d mxml/*.o libsensors/*.d libsensors/*.o $(TARGET) escape events.xml events_xml.h defaults_xml.h
diff --git a/tools/gator/daemon/defaults.xml b/tools/gator/daemon/defaults.xml
new file mode 100644
index 00000000000..39a0f656f7e
--- /dev/null
+++ b/tools/gator/daemon/defaults.xml
@@ -0,0 +1,67 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<configurations revision="3">
3 <configuration counter="ARM_ARM11_ccnt" event="0xff"/>
4 <configuration counter="ARM_ARM11_cnt0" event="0x7"/>
5 <configuration counter="ARM_ARM11_cnt1" event="0xb"/>
6 <configuration counter="ARM_ARM11MPCore_ccnt" event="0xff"/>
7 <configuration counter="ARM_ARM11MPCore_cnt0" event="0x08"/>
8 <configuration counter="ARM_ARM11MPCore_cnt1" event="0x0b"/>
9 <configuration counter="ARMv7_Cortex_A5_ccnt" event="0xff"/>
10 <configuration counter="ARMv7_Cortex_A5_cnt0" event="0x8"/>
11 <configuration counter="ARMv7_Cortex_A5_cnt1" event="0x1"/>
12 <configuration counter="ARMv7_Cortex_A7_ccnt" event="0xff"/>
13 <configuration counter="ARMv7_Cortex_A7_cnt0" event="0x08"/>
14 <configuration counter="ARMv7_Cortex_A7_cnt1" event="0x10"/>
15 <configuration counter="ARMv7_Cortex_A7_cnt2" event="0x16"/>
16 <configuration counter="ARMv7_Cortex_A8_ccnt" event="0xff"/>
17 <configuration counter="ARMv7_Cortex_A8_cnt0" event="0x8"/>
18 <configuration counter="ARMv7_Cortex_A8_cnt1" event="0x44"/>
19 <configuration counter="ARMv7_Cortex_A8_cnt2" event="0x43"/>
20 <configuration counter="ARMv7_Cortex_A8_cnt3" event="0x10"/>
21 <configuration counter="ARMv7_Cortex_A9_ccnt" event="0xff"/>
22 <configuration counter="ARMv7_Cortex_A9_cnt0" event="0x68"/>
23 <configuration counter="ARMv7_Cortex_A9_cnt1" event="0x06"/>
24 <configuration counter="ARMv7_Cortex_A9_cnt2" event="0x07"/>
25 <configuration counter="ARMv7_Cortex_A9_cnt3" event="0x03"/>
26 <configuration counter="ARMv7_Cortex_A9_cnt4" event="0x04"/>
27 <configuration counter="ARMv7_Cortex_A12_ccnt" event="0xff"/>
28 <configuration counter="ARMv7_Cortex_A12_cnt0" event="0x08"/>
29 <configuration counter="ARMv7_Cortex_A12_cnt1" event="0x16"/>
30 <configuration counter="ARMv7_Cortex_A12_cnt2" event="0x10"/>
31 <configuration counter="ARMv7_Cortex_A12_cnt3" event="0x19"/>
32 <configuration counter="ARMv7_Cortex_A15_ccnt" event="0xff"/>
33 <configuration counter="ARMv7_Cortex_A15_cnt0" event="0x8"/>
34 <configuration counter="ARMv7_Cortex_A15_cnt1" event="0x16"/>
35 <configuration counter="ARMv7_Cortex_A15_cnt2" event="0x10"/>
36 <configuration counter="ARMv7_Cortex_A15_cnt3" event="0x19"/>
37 <configuration counter="ARM_Cortex-A53_ccnt" event="0x11"/>
38 <configuration counter="ARM_Cortex-A53_cnt0" event="0x8"/>
39 <configuration counter="ARM_Cortex-A53_cnt1" event="0x16"/>
40 <configuration counter="ARM_Cortex-A53_cnt2" event="0x10"/>
41 <configuration counter="ARM_Cortex-A53_cnt3" event="0x19"/>
42 <configuration counter="ARM_Cortex-A57_ccnt" event="0x11"/>
43 <configuration counter="ARM_Cortex-A57_cnt0" event="0x8"/>
44 <configuration counter="ARM_Cortex-A57_cnt1" event="0x16"/>
45 <configuration counter="ARM_Cortex-A57_cnt2" event="0x10"/>
46 <configuration counter="ARM_Cortex-A57_cnt3" event="0x19"/>
47 <configuration counter="Scorpion_ccnt" event="0xff"/>
48 <configuration counter="Scorpion_cnt0" event="0x08"/>
49 <configuration counter="Scorpion_cnt1" event="0x10"/>
50 <configuration counter="ScorpionMP_ccnt" event="0xff"/>
51 <configuration counter="ScorpionMP_cnt0" event="0x08"/>
52 <configuration counter="ScorpionMP_cnt1" event="0x10"/>
53 <configuration counter="Krait_ccnt" event="0xff"/>
54 <configuration counter="Krait_cnt0" event="0x08"/>
55 <configuration counter="Krait_cnt1" event="0x10"/>
56 <configuration counter="Linux_block_rq_wr"/>
57 <configuration counter="Linux_block_rq_rd"/>
58 <configuration counter="Linux_meminfo_memused"/>
59 <configuration counter="Linux_meminfo_memfree"/>
60 <configuration counter="Linux_power_cpu_freq"/>
61 <configuration counter="ARM_Mali-4xx_fragment"/>
62 <configuration counter="ARM_Mali-4xx_vertex"/>
63 <configuration counter="ARM_Mali-T6xx_fragment" cores="1"/>
64 <configuration counter="ARM_Mali-T6xx_vertex" cores="1"/>
65 <configuration counter="ARM_Mali-T6xx_opencl" cores="1"/>
66 <configuration counter="L2C-310_cnt0" event="0x1"/>
67</configurations>
diff --git a/tools/gator/daemon/escape.c b/tools/gator/daemon/escape.c
new file mode 100644
index 00000000000..2b0863aaf42
--- /dev/null
+++ b/tools/gator/daemon/escape.c
@@ -0,0 +1,75 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9/*
10 * The Makefile in the daemon folder builds and executes 'escape'
11 * 'escape' creates configuration_xml.h from configuration.xml and events_xml.h from events-*.xml
12 * these genereated xml files are then #included and built as part of the gatord binary
13 */
14
15#include <errno.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <ctype.h>
20
21static void print_escaped_path(char *path) {
22 if (isdigit(*path)) {
23 printf("__");
24 }
25 for (; *path != '\0'; ++path) {
26 printf("%c", isalnum(*path) ? *path : '_');
27 }
28}
29
30int main(int argc, char *argv[]) {
31 int i;
32 char *path;
33 FILE *in = NULL;
34 int ch;
35 unsigned int len = 0;
36
37 for (i = 1; i < argc && argv[i][0] == '-'; ++i) ;
38 if (i == argc) {
39 fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
40 return EXIT_FAILURE;
41 }
42 path = argv[i];
43
44 errno = 0;
45 if ((in = fopen(path, "r")) == NULL) {
46 fprintf(stderr, "Unable to open '%s': %s\n", path, strerror(errno));
47 return EXIT_FAILURE;
48 }
49
50 printf("static const unsigned char ");
51 print_escaped_path(path);
52 printf("[] = {");
53 for (;;) {
54 ch = fgetc(in);
55 if (len != 0) {
56 printf(",");
57 }
58 if (len % 12 == 0) {
59 printf("\n ");
60 }
61 // Write out a null character after the contents of the file but do not increment len
62 printf(" 0x%.2x", (ch == EOF ? 0 : ch));
63 if (ch == EOF) {
64 break;
65 }
66 ++len;
67 }
68 printf("\n};\nstatic const unsigned int ");
69 print_escaped_path(path);
70 printf("_len = %i;\n", len);
71
72 fclose(in);
73
74 return EXIT_SUCCESS;
75}
diff --git a/tools/gator/daemon/events-ARM11.xml b/tools/gator/daemon/events-ARM11.xml
new file mode 100644
index 00000000000..57e32354631
--- /dev/null
+++ b/tools/gator/daemon/events-ARM11.xml
@@ -0,0 +1,39 @@
1 <counter_set name="ARM_ARM11_cnt" count="3"/>
2 <category name="ARM11" counter_set="ARM_ARM11_cnt" per_cpu="yes">
3 <event counter="ARM_ARM11_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Cache" name="Inst miss" description="Instruction cache miss to a cacheable location, which requires a fetch from external memory"/>
5 <event event="0x01" title="Pipeline" name="Instruction stall" description="Stall because instruction buffer cannot deliver an instruction"/>
6 <event event="0x02" title="Pipeline" name="Data stall" description="Stall because of a data dependency"/>
7 <event event="0x03" title="Cache" name="Inst micro TLB miss" description="Instruction MicroTLB miss (unused on ARM1156)"/>
8 <event event="0x04" title="Cache" name="Data micro TLB miss" description="Data MicroTLB miss (unused on ARM1156)"/>
9 <event event="0x05" title="Branch" name="Instruction executed" description="Branch instruction executed, branch might or might not have changed program flow"/>
10 <event event="0x06" title="Branch" name="Mispredicted" description="Branch mis-predicted"/>
11 <event event="0x07" title="Instruction" name="Executed" description="Instructions executed"/>
12 <event event="0x09" title="Cache" name="Data access" description="Data cache access, not including Cache operations"/>
13 <event event="0x0a" title="Cache" name="Data all access" description="Data cache access, not including Cache Operations regardless of whether or not the location is cacheable"/>
14 <event event="0x0b" title="Cache" name="Data miss" description="Data cache miss, not including Cache Operations"/>
15 <event event="0x0c" title="Cache" name="Write-back" description="Data cache write-back"/>
16 <event event="0x0d" title="Program Counter" name="SW change" description="Software changed the PC"/>
17 <event event="0x0f" title="Cache " name="TLB miss" description="Main TLB miss (unused on ARM1156)"/>
18 <event event="0x10" title="External" name="Access" description="Explicit external data or peripheral access"/>
19 <event event="0x11" title="Cache" name="Data miss" description="Stall because of Load Store Unit request queue being full"/>
20 <event event="0x12" title="Write Buffer" name="Drains" description="The number of times the Write Buffer was drained because of a Data Synchronization Barrier command or Strongly Ordered operation"/>
21 <event event="0x13" title="Disable Interrupts" name="FIQ" description="The number of cycles which FIQ interrupts are disabled (ARM1156 only)"/>
22 <event event="0x14" title="Disable Interrupts" name="IRQ" description="The number of cycles which IRQ interrupts are disabled (ARM1156 only)"/>
23 <event event="0x20" title="ETM" name="ETMEXTOUT[0]" description="ETMEXTOUT[0] signal was asserted for a cycle"/>
24 <event event="0x21" title="ETM" name="ETMEXTOUT[1]" description="ETMEXTOUT[1] signal was asserted for a cycle"/>
25 <event event="0x22" title="ETM" name="ETMEXTOUT[0,1]" description="ETMEXTOUT[0] or ETMEXTOUT[1] was asserted"/>
26 <event event="0x23" title="Procedure" name="Calls" description="Procedure call instruction executed"/>
27 <event event="0x24" title="Procedure" name="Returns" description="Procedure return instruction executed"/>
28 <event event="0x25" title="Procedure" name="Return and predicted" description="Procedure return instruction executed and return address predicted"/>
29 <event event="0x26" title="Procedure" name="Return and mispredicted" description="Procedure return instruction executed and return address predicted incorrectly"/>
30 <event event="0x30" title="Cache" name="Inst tag or parity error" description="Instruction cache Tag or Valid RAM parity error (ARM1156 only)"/>
31 <event event="0x31" title="Cache" name="Inst parity error" description="Instruction cache RAM parity error (ARM1156 only)"/>
32 <event event="0x32" title="Cache" name="Data tag or parity error" description="Data cache Tag or Valid RAM parity error (ARM1156 only)"/>
33 <event event="0x33" title="Cache" name="Data parity error" description="Data cache RAM parity error (ARM1156 only)"/>
34 <event event="0x34" title="ITCM" name="Error" description="ITCM error (ARM1156 only)"/>
35 <event event="0x35" title="DTCM" name="Error" description="DTCM error (ARM1156 only)"/>
36 <event event="0x36" title="Procedure" name="Return address pop" description="Procedure return address popped off the return stack (ARM1156 only)"/>
37 <event event="0x37" title="Procedure" name="Return address misprediction" description="Procedure return address popped off the return stack has been incorrectly predicted by the PFU (ARM1156 only)"/>
38 <event event="0x38" title="Cache" name="Data dirty parity error" description="Data cache Dirty RAM parity error (ARM1156 only)"/>
39 </category>
diff --git a/tools/gator/daemon/events-ARM11MPCore.xml b/tools/gator/daemon/events-ARM11MPCore.xml
new file mode 100644
index 00000000000..2d5c5e199e6
--- /dev/null
+++ b/tools/gator/daemon/events-ARM11MPCore.xml
@@ -0,0 +1,26 @@
1 <counter_set name="ARM_ARM11MPCore_cnt" count="3"/>
2 <category name="ARM11MPCore" counter_set="ARM_ARM11MPCore_cnt" per_cpu="yes">
3 <event counter="ARM_ARM11MPCore_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Cache" name="Inst miss" description="Instruction cache miss to a cacheable location, which requires a fetch from external memory"/>
5 <event event="0x01" title="Pipeline" name="Instruction stall" description="Stall because instruction buffer cannot deliver an instruction"/>
6 <event event="0x02" title="Pipeline" name="Data stall" description="Stall because of a data dependency"/>
7 <event event="0x03" title="Cache" name="Inst micro TLB miss" description="Instruction MicroTLB miss (unused on ARM1156)"/>
8 <event event="0x04" title="Cache" name="Data micro TLB miss" description="Data MicroTLB miss (unused on ARM1156)"/>
9 <event event="0x05" title="Branch" name="Instruction executed" description="Branch instructions executed, branch might or might not have changed program flow"/>
10 <event event="0x06" title="Branch" name="Not predicted" description="Branch not predicted"/>
11 <event event="0x07" title="Branch" name="Mispredicted" description="Branch mispredicted"/>
12 <event event="0x08" title="Core" name="Instructions" description="Instructions executed"/>
13 <event event="0x09" title="Core" name="Folded Instructions" description="Folded instructions executed"/>
14 <event event="0x0a" title="Cache" name="Data read access" description="Data cache read access, not including cache operations"/>
15 <event event="0x0b" title="Cache" name="Data read miss" description="Data cache miss, not including Cache Operations"/>
16 <event event="0x0c" title="Cache" name="Data write access" description="Data cache write access"/>
17 <event event="0x0d" title="Cache" name="Data write miss" description="Data cache write miss"/>
18 <event event="0x0e" title="Cache" name="Data line eviction" description="Data cache line eviction, not including cache operations"/>
19 <event event="0x0f" title="Branch" name="PC change w/o mode change" description="Software changed the PC and there is not a mode change"/>
20 <event event="0x10" title="Cache " name="TLB miss" description="Main TLB miss"/>
21 <event event="0x11" title="External" name="External Memory request" description="External memory request (cache refill, noncachable, write-back)"/>
22 <event event="0x12" title="Cache" name="Stall" description="Stall because of Load Store Unit request queue being full"/>
23 <event event="0x13" title="Write Buffer" name="Drains" description="The number of times the Write Buffer was drained because of LSU ordering constraints or CP15 operations (Data Synchronization Barrier command) or Strongly Ordered operation"/>
24 <event event="0x14" title="Write Buffer" name="Write Merges" description="Buffered write merged in a store buffer slot"/>
25 <event event="0xFF" title="Core" name="Cycle counter" description="An increment each cycle"/>
26 </category>
diff --git a/tools/gator/daemon/events-CCI-400.xml b/tools/gator/daemon/events-CCI-400.xml
new file mode 100644
index 00000000000..20002efd154
--- /dev/null
+++ b/tools/gator/daemon/events-CCI-400.xml
@@ -0,0 +1,98 @@
1 <counter_set name="CCI_400_cnt" count="4"/>
2 <category name="CCI-400" counter_set="CCI_400_cnt" per_cpu="no" supports_event_based_sampling="yes">
3 <event counter="CCI_400_ccnt" event="0xff" title="CCI-400 Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
4 <option_set name="Slave">
5 <option event_delta="0x00" name="S0" description="Slave interface 0"/>
6 <option event_delta="0x20" name="S1" description="Slave interface 1"/>
7 <option event_delta="0x40" name="S2" description="Slave interface 2"/>
8 <option event_delta="0x60" name="S3" description="Slave interface 3"/>
9 <option event_delta="0x80" name="S4" description="Slave interface 4"/>
10 </option_set>
11 <event event="0x00" option_set="Slave" title="CCI-400" name="Read: any" description="Read request handshake: any"/>
12 <event event="0x01" option_set="Slave" title="CCI-400" name="Read: transaction" description="Read request handshake: device transaction"/>
13 <event event="0x02" option_set="Slave" title="CCI-400" name="Read: normal" description="Read request handshake: normal, non-shareable or system-shareable, but not barrier or cache maintenance operation"/>
14 <event event="0x03" option_set="Slave" title="CCI-400" name="Read: shareable" description="Read request handshake: inner- or outer-shareable, but not barrier, DVM message or cache maintenance operation"/>
15 <event event="0x04" option_set="Slave" title="CCI-400" name="Read: cache" description="Read request handshake: cache maintenance operation, CleanInvalid, CleanShared, MakeInvalid"/>
16 <event event="0x05" option_set="Slave" title="CCI-400" name="Read: memory barrier" description="Read request handshake: memory barrier"/>
17 <event event="0x06" option_set="Slave" title="CCI-400" name="Read: sync barrier" description="Read request handshake: synchronization barrier"/>
18 <event event="0x07" option_set="Slave" title="CCI-400" name="Read: DVM message, no sync" description="Read request handshake: DVM message, not synchronization"/>
19 <event event="0x08" option_set="Slave" title="CCI-400" name="Read: DVM message, sync" description="Read request handshake: DVM message, synchronization"/>
20 <event event="0x09" option_set="Slave" title="CCI-400" name="Read: stall" description="Read request stall cycle because the transaction tracker is full. Increase SIx_R_MAX to avoid this stall"/>
21 <event event="0x0a" option_set="Slave" title="CCI-400" name="Read data last handshake" description="Read data last handshake: data returned from the snoop instead of from downstream"/>
22 <event event="0x0b" option_set="Slave" title="CCI-400" name="Read data stall cycle" description="Read data stall cycle: RVALIDS is HIGH, RREADYS is LOW"/>
23 <event event="0x0c" option_set="Slave" title="CCI-400" name="Write: any" description="Write request handshake: any"/>
24 <event event="0x0d" option_set="Slave" title="CCI-400" name="Write: transaction" description="Write request handshake: device transaction"/>
25 <event event="0x0e" option_set="Slave" title="CCI-400" name="Write: normal" description="Write request handshake: normal, non-shareable, or system-shareable, but not barrier"/>
26 <event event="0x0f" option_set="Slave" title="CCI-400" name="Write: shareable" description="Write request handshake: inner- or outer-shareable, WriteBack or WriteClean"/>
27 <event event="0x10" option_set="Slave" title="CCI-400" name="Write: WriteUnique" description="Write request handshake: WriteUnique"/>
28 <event event="0x11" option_set="Slave" title="CCI-400" name="Write: WriteLineUnique" description="Write request handshake: WriteLineUnique"/>
29 <event event="0x12" option_set="Slave" title="CCI-400" name="Write: Evict" description="Write request handshake: Evict"/>
30 <event event="0x13" option_set="Slave" title="CCI-400" name="Write stall: tracker full" description="Write request stall cycle because the transaction tracker is full. Increase SIx_W_MAX to avoid this stall"/>
31 <option_set name="Master">
32 <option event_delta="0xa0" name="M0" description="Master interface 0"/>
33 <option event_delta="0xc0" name="M1" description="Master interface 1"/>
34 <option event_delta="0xe0" name="M2" description="Master interface 2"/>
35 </option_set>
36 <event event="0x14" option_set="Master" title="CCI-400" name="Retry fetch" description="RETRY of speculative fetch transaction"/>
37 <event event="0x15" option_set="Master" title="CCI-400" name="Read stall: address hazard" description="Read request stall cycle because of an address hazard"/>
38 <event event="0x16" option_set="Master" title="CCI-400" name="Read stall: ID hazard" description="Read request stall cycle because of an ID hazard"/>
39 <event event="0x17" option_set="Master" title="CCI-400" name="Read stall: tracker full" description="Read request stall cycle because the transaction tracker is full. Increase MIx_R_MAX to avoid this stall. See the CoreLink CCI-400 Cache Coherent Interconnect Integration Manual"/>
40 <event event="0x18" option_set="Master" title="CCI-400" name="Read stall: barrier hazard" description="Read request stall cycle because of a barrier hazard"/>
41 <event event="0x19" option_set="Master" title="CCI-400" name="Write stall: barrier hazard" description="Write request stall cycle because of a barrier hazard"/>
42 <event event="0x1a" option_set="Master" title="CCI-400" name="Write stall: tracker full" description="Write request stall cycle because the transaction tracker is full. Increase MIx_W_MAX to avoid this stall. See the CoreLink CCI-400 Cache Coherent Interconnect Integration Manual"/>
43 </category>
44 <counter_set name="CCI_400-r1_cnt" count="4"/>
45 <category name="CCI-400" counter_set="CCI_400-r1_cnt" per_cpu="no" supports_event_based_sampling="yes">
46 <event counter="CCI_400-r1_ccnt" event="0xff" title="CCI-400 Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
47 <option_set name="Slave">
48 <option event_delta="0x00" name="S0" description="Slave interface 0"/>
49 <option event_delta="0x20" name="S1" description="Slave interface 1"/>
50 <option event_delta="0x40" name="S2" description="Slave interface 2"/>
51 <option event_delta="0x60" name="S3" description="Slave interface 3"/>
52 <option event_delta="0x80" name="S4" description="Slave interface 4"/>
53 </option_set>
54 <event event="0x00" option_set="Slave" title="CCI-400" name="Read: any" description="Read request handshake: any"/>
55 <event event="0x01" option_set="Slave" title="CCI-400" name="Read: transaction" description="Read request handshake: device transaction"/>
56 <event event="0x02" option_set="Slave" title="CCI-400" name="Read: normal" description="Read request handshake: normal, non-shareable or system-shareable, but not barrier or cache maintenance operation"/>
57 <event event="0x03" option_set="Slave" title="CCI-400" name="Read: shareable" description="Read request handshake: inner- or outer-shareable, but not barrier, DVM message or cache maintenance operation"/>
58 <event event="0x04" option_set="Slave" title="CCI-400" name="Read: cache" description="Read request handshake: cache maintenance operation"/>
59 <event event="0x05" option_set="Slave" title="CCI-400" name="Read: memory barrier" description="Read request handshake: memory barrier"/>
60 <event event="0x06" option_set="Slave" title="CCI-400" name="Read: sync barrier" description="Read request handshake: synchronization barrier"/>
61 <event event="0x07" option_set="Slave" title="CCI-400" name="Read: DVM message, no sync" description="Read request handshake: DVM message, not synchronization"/>
62 <event event="0x08" option_set="Slave" title="CCI-400" name="Read: DVM message, sync" description="Read request handshake: DVM message, synchronization"/>
63 <event event="0x09" option_set="Slave" title="CCI-400" name="Read: stall" description="Read request stall cycle because the transaction tracker is full. Increase SIx_R_MAX to avoid this stall"/>
64 <event event="0x0a" option_set="Slave" title="CCI-400" name="Read data last handshake" description="Read data last handshake: data returned from the snoop instead of from downstream"/>
65 <event event="0x0b" option_set="Slave" title="CCI-400" name="Read data stall cycle" description="Read data stall cycle: RVALIDS is HIGH, RREADYS is LOW"/>
66 <event event="0x0c" option_set="Slave" title="CCI-400" name="Write: any" description="Write request handshake: any"/>
67 <event event="0x0d" option_set="Slave" title="CCI-400" name="Write: transaction" description="Write request handshake: device transaction"/>
68 <event event="0x0e" option_set="Slave" title="CCI-400" name="Write: normal" description="Write request handshake: normal, non-shareable, or system-shareable, but not barrier"/>
69 <event event="0x0f" option_set="Slave" title="CCI-400" name="Write: shareable" description="Write request handshake: inner- or outer-shareable, WriteBack or WriteClean"/>
70 <event event="0x10" option_set="Slave" title="CCI-400" name="Write: WriteUnique" description="Write request handshake: WriteUnique"/>
71 <event event="0x11" option_set="Slave" title="CCI-400" name="Write: WriteLineUnique" description="Write request handshake: WriteLineUnique"/>
72 <event event="0x12" option_set="Slave" title="CCI-400" name="Write: Evict" description="Write request handshake: Evict"/>
73 <event event="0x13" option_set="Slave" title="CCI-400" name="Write stall: tracker full" description="Write request stall cycle because the transaction tracker is full. Increase SIx_W_MAX to avoid this stall"/>
74 <event event="0x14" option_set="Slave" title="CCI-400" name="Read stall: slave hazard" description="Read request stall cycle because of a slave interface ID hazard"/>
75 <option_set name="Master">
76 <option event_delta="0xa0" name="M0" description="Master interface 0"/>
77 <option event_delta="0xc0" name="M1" description="Master interface 1"/>
78 <option event_delta="0xe0" name="M2" description="Master interface 2"/>
79 </option_set>
80 <event event="0x00" option_set="Master" title="CCI-400" name="Retry fetch" description="RETRY of speculative fetch transaction"/>
81 <event event="0x01" option_set="Master" title="CCI-400" name="Read stall: address hazard" description="Stall cycle because of an address hazard. A read or write invalidation is stalled because of an outstanding transaction to an overlapping address"/>
82 <event event="0x02" option_set="Master" title="CCI-400" name="Read stall: ID hazard" description="Read request stall cycle because of a master interface ID hazard"/>
83 <event event="0x03" option_set="Master" title="CCI-400" name="Read stall: tracker full" description="A read request with a QoS value in the high priority group is stalled for a cycle because the read transaction queue is full. Increase MIx_R_MAX to avoid this stall"/>
84 <event event="0x04" option_set="Master" title="CCI-400" name="Read stall: barrier hazard" description="Read request stall cycle because of a barrier hazard"/>
85 <event event="0x05" option_set="Master" title="CCI-400" name="Write stall: barrier hazard" description="Write request stall cycle because of a barrier hazard"/>
86 <event event="0x06" option_set="Master" title="CCI-400" name="Write stall: tracker full" description="A write request is stalled for a cycle because the write transaction tracker is full. Increase MIx_W_MAX to avoid this stall"/>
87 <event event="0x07" option_set="Master" title="CCI-400" name="Read Stall: Low Priority" description="A read request with a QoS value in the low priority group is stalled for a cycle because there are no slots available in the read queue for the low priority group"/>
88 <event event="0x08" option_set="Master" title="CCI-400" name="Read Stall: Medium Priority" description="A read request with a QoS value in the medium priority group is stalled for a cycle because there are no slots available in the read queue for the medium priority group"/>
89 <event event="0x09" option_set="Master" title="CCI-400" name="Read Stall: VN0" description="A read request is stalled for a cycle while it was waiting for a QVN token on VN0"/>
90 <event event="0x0a" option_set="Master" title="CCI-400" name="Read Stall: VN1" description="A read request is stalled for a cycle while it was waiting for a QVN token on VN1"/>
91 <event event="0x0b" option_set="Master" title="CCI-400" name="Read Stall: VN2" description="A read request is stalled for a cycle while it was waiting for a QVN token on VN2"/>
92 <event event="0x0c" option_set="Master" title="CCI-400" name="Read Stall: VN3" description="A read request is stalled for a cycle while it was waiting for a QVN token on VN3"/>
93 <event event="0x0d" option_set="Master" title="CCI-400" name="Write Stall: VN0" description="A write request is stalled for a cycle while it was waiting for a QVN token on VN0"/>
94 <event event="0x0e" option_set="Master" title="CCI-400" name="Write Stall: VN1" description="A write request is stalled for a cycle while it was waiting for a QVN token on VN1"/>
95 <event event="0x0f" option_set="Master" title="CCI-400" name="Write Stall: VN2" description="A write request is stalled for a cycle while it was waiting for a QVN token on VN2"/>
96 <event event="0x10" option_set="Master" title="CCI-400" name="Write Stall: VN" description="A write request is stalled for a cycle while it was waiting for a QVN token on VN"/>
97 <event event="0x11" option_set="Master" title="CCI-400" name="WriteUnique or WriteLineUnique Stall" description="A WriteUnique or WriteLineUnique request is stalled for a cycle because of an address hazard"/>
98 </category>
diff --git a/tools/gator/daemon/events-CCN-504.xml b/tools/gator/daemon/events-CCN-504.xml
new file mode 100644
index 00000000000..6ef3e648371
--- /dev/null
+++ b/tools/gator/daemon/events-CCN-504.xml
@@ -0,0 +1,113 @@
1 <counter_set name="CCN-504_cnt" count="4"/>
2 <category name="CCN-504" counter_set="CCN-504_cnt">
3 <event counter="CCN-504_ccnt" title="CCN-504 Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
4 <option_set name="XP_Region">
5 <option event_delta="0x400000" name="XP 0" description="Crosspoint 0"/>
6 <option event_delta="0x410000" name="XP 1" description="Crosspoint 1"/>
7 <option event_delta="0x420000" name="XP 2" description="Crosspoint 2"/>
8 <option event_delta="0x430000" name="XP 3" description="Crosspoint 3"/>
9 <option event_delta="0x440000" name="XP 4" description="Crosspoint 4"/>
10 <option event_delta="0x450000" name="XP 5" description="Crosspoint 5"/>
11 <option event_delta="0x460000" name="XP 6" description="Crosspoint 6"/>
12 <option event_delta="0x470000" name="XP 7" description="Crosspoint 7"/>
13 <option event_delta="0x480000" name="XP 8" description="Crosspoint 8"/>
14 <option event_delta="0x490000" name="XP 9" description="Crosspoint 9"/>
15 <option event_delta="0x4A0000" name="XP 10" description="Crosspoint 10"/>
16 </option_set>
17 <event event="0x0801" option_set="XP_Region" title="CCN-504" name="Bus 0: REQ: H-bit" description="Bus 0: REQ: Set H-bit, signaled when this XP sets the H-bit."/>
18 <event event="0x0802" option_set="XP_Region" title="CCN-504" name="Bus 0: REQ: S-bit" description="Bus 0: REQ: Set S-bit, signaled when this XP sets the S-bit."/>
19 <event event="0x0803" option_set="XP_Region" title="CCN-504" name="Bus 0: REQ: P-Cnt" description="Bus 0: REQ: Set P-Cnt, signaled when this XP sets the P-Cnt. This is not applicable for the SNP VC."/>
20 <event event="0x0804" option_set="XP_Region" title="CCN-504" name="Bus 0: REQ: TknV" description="Bus 0: REQ: No TknV, signaled when this XP transmits a valid packet."/>
21 <event event="0x0809" option_set="XP_Region" title="CCN-504" name="Bus 1: REQ: H-bit" description="Bus 1: REQ: Set H-bit, signaled when this XP sets the H-bit."/>
22 <event event="0x080A" option_set="XP_Region" title="CCN-504" name="Bus 1: REQ: S-bit" description="Bus 1: REQ: Set S-bit, signaled when this XP sets the S-bit."/>
23 <event event="0x080B" option_set="XP_Region" title="CCN-504" name="Bus 1: REQ: P-Cnt" description="Bus 1: REQ: Set P-Cnt, signaled when this XP sets the P-Cnt. This is not applicable for the SNP VC."/>
24 <event event="0x080C" option_set="XP_Region" title="CCN-504" name="Bus 1: REQ: TknV" description="Bus 1: REQ: No TknV, signaled when this XP transmits a valid packet."/>
25 <event event="0x0811" option_set="XP_Region" title="CCN-504" name="Bus 0: RSP: H-bit" description="Bus 0: RSP: Set H-bit, signaled when this XP sets the H-bit."/>
26 <event event="0x0812" option_set="XP_Region" title="CCN-504" name="Bus 0: RSP: S-bit" description="Bus 0: RSP: Set S-bit, signaled when this XP sets the S-bit."/>
27 <event event="0x0813" option_set="XP_Region" title="CCN-504" name="Bus 0: RSP: P-Cnt" description="Bus 0: RSP: Set P-Cnt, signaled when this XP sets the P-Cnt. This is not applicable for the SNP VC."/>
28 <event event="0x0814" option_set="XP_Region" title="CCN-504" name="Bus 0: RSP: TknV" description="Bus 0: RSP: No TknV, signaled when this XP transmits a valid packet."/>
29 <event event="0x0819" option_set="XP_Region" title="CCN-504" name="Bus 1: RSP: H-bit" description="Bus 1: RSP: Set H-bit, signaled when this XP sets the H-bit."/>
30 <event event="0x081A" option_set="XP_Region" title="CCN-504" name="Bus 1: RSP: S-bit" description="Bus 1: RSP: Set S-bit, signaled when this XP sets the S-bit."/>
31 <event event="0x081B" option_set="XP_Region" title="CCN-504" name="Bus 1: RSP: P-Cnt" description="Bus 1: RSP: Set P-Cnt, signaled when this XP sets the P-Cnt. This is not applicable for the SNP VC."/>
32 <event event="0x081C" option_set="XP_Region" title="CCN-504" name="Bus 1: RSP: TknV" description="Bus 1: RSP: No TknV, signaled when this XP transmits a valid packet."/>
33 <event event="0x0821" option_set="XP_Region" title="CCN-504" name="Bus 0: SNP: H-bit" description="Bus 0: SNP: Set H-bit, signaled when this XP sets the H-bit."/>
34 <event event="0x0822" option_set="XP_Region" title="CCN-504" name="Bus 0: SNP: S-bit" description="Bus 0: SNP: Set S-bit, signaled when this XP sets the S-bit."/>
35 <event event="0x0823" option_set="XP_Region" title="CCN-504" name="Bus 0: SNP: P-Cnt" description="Bus 0: SNP: Set P-Cnt, signaled when this XP sets the P-Cnt. This is not applicable for the SNP VC."/>
36 <event event="0x0824" option_set="XP_Region" title="CCN-504" name="Bus 0: SNP: TknV" description="Bus 0: SNP: No TknV, signaled when this XP transmits a valid packet."/>
37 <event event="0x0829" option_set="XP_Region" title="CCN-504" name="Bus 1: SNP: H-bit" description="Bus 1: SNP: Set H-bit, signaled when this XP sets the H-bit."/>
38 <event event="0x082A" option_set="XP_Region" title="CCN-504" name="Bus 1: SNP: S-bit" description="Bus 1: SNP: Set S-bit, signaled when this XP sets the S-bit."/>
39 <event event="0x082B" option_set="XP_Region" title="CCN-504" name="Bus 1: SNP: P-Cnt" description="Bus 1: SNP: Set P-Cnt, signaled when this XP sets the P-Cnt. This is not applicable for the SNP VC."/>
40 <event event="0x082C" option_set="XP_Region" title="CCN-504" name="Bus 1: SNP: TknV" description="Bus 1: SNP: No TknV, signaled when this XP transmits a valid packet."/>
41 <event event="0x0831" option_set="XP_Region" title="CCN-504" name="Bus 0: DAT: H-bit" description="Bus 0: DAT: Set H-bit, signaled when this XP sets the H-bit."/>
42 <event event="0x0832" option_set="XP_Region" title="CCN-504" name="Bus 0: DAT: S-bit" description="Bus 0: DAT: Set S-bit, signaled when this XP sets the S-bit."/>
43 <event event="0x0833" option_set="XP_Region" title="CCN-504" name="Bus 0: DAT: P-Cnt" description="Bus 0: DAT: Set P-Cnt, signaled when this XP sets the P-Cnt. This is not applicable for the SNP VC."/>
44 <event event="0x0834" option_set="XP_Region" title="CCN-504" name="Bus 0: DAT: TknV" description="Bus 0: DAT: No TknV, signaled when this XP transmits a valid packet."/>
45 <event event="0x0839" option_set="XP_Region" title="CCN-504" name="Bus 1: DAT: H-bit" description="Bus 1: DAT: Set H-bit, signaled when this XP sets the H-bit."/>
46 <event event="0x083A" option_set="XP_Region" title="CCN-504" name="Bus 1: DAT: S-bit" description="Bus 1: DAT: Set S-bit, signaled when this XP sets the S-bit."/>
47 <event event="0x083B" option_set="XP_Region" title="CCN-504" name="Bus 1: DAT: P-Cnt" description="Bus 1: DAT: Set P-Cnt, signaled when this XP sets the P-Cnt. This is not applicable for the SNP VC."/>
48 <event event="0x083C" option_set="XP_Region" title="CCN-504" name="Bus 1: DAT: TknV" description="Bus 1: DAT: No TknV, signaled when this XP transmits a valid packet."/>
49 <event event="0x0871" option_set="XP_Region" title="CCN-504" name="Bus 0: DATB: H-bit" description="Bus 0: DATB: Set H-bit, signaled when this XP sets the H-bit."/>
50 <event event="0x0872" option_set="XP_Region" title="CCN-504" name="Bus 0: DATB: S-bit" description="Bus 0: DATB: Set S-bit, signaled when this XP sets the S-bit."/>
51 <event event="0x0873" option_set="XP_Region" title="CCN-504" name="Bus 0: DATB: P-Cnt" description="Bus 0: DATB: Set P-Cnt, signaled when this XP sets the P-Cnt. This is not applicable for the SNP VC."/>
52 <event event="0x0874" option_set="XP_Region" title="CCN-504" name="Bus 0: DATB: TknV" description="Bus 0: DATB: No TknV, signaled when this XP transmits a valid packet."/>
53 <event event="0x0879" option_set="XP_Region" title="CCN-504" name="Bus 1: DATB: H-bit" description="Bus 1: DATB: Set H-bit, signaled when this XP sets the H-bit."/>
54 <event event="0x087A" option_set="XP_Region" title="CCN-504" name="Bus 1: DATB: S-bit" description="Bus 1: DATB: Set S-bit, signaled when this XP sets the S-bit."/>
55 <event event="0x087B" option_set="XP_Region" title="CCN-504" name="Bus 1: DATB: P-Cnt" description="Bus 1: DATB: Set P-Cnt, signaled when this XP sets the P-Cnt. This is not applicable for the SNP VC."/>
56 <event event="0x087C" option_set="XP_Region" title="CCN-504" name="Bus 1: DATB: TknV" description="Bus 1: DATB: No TknV, signaled when this XP transmits a valid packet."/>
57 <option_set name="HN-F_Region">
58 <option event_delta="0x200000" name="HN-F 3" description="Fully-coherent Home Node 3"/>
59 <option event_delta="0x210000" name="HN-F 5" description="Fully-coherent Home Node 5"/>
60 <option event_delta="0x220000" name="HN-F 7" description="Fully-coherent Home Node 7"/>
61 <option event_delta="0x230000" name="HN-F 8" description="Fully-coherent Home Node 8"/>
62 <option event_delta="0x240000" name="HN-F 13" description="Fully-coherent Home Node 13"/>
63 <option event_delta="0x250000" name="HN-F 15" description="Fully-coherent Home Node 15"/>
64 <option event_delta="0x260000" name="HN-F 17" description="Fully-coherent Home Node 17"/>
65 <option event_delta="0x270000" name="HN-F 18" description="Fully-coherent Home Node 18"/>
66 </option_set>
67 <event event="0x0401" option_set="HN-F_Region" title="CCN-504" name="Cache Miss" description="Counts the total cache misses. This is the first time lookup result, and is high priority."/>
68 <event event="0x0402" option_set="HN-F_Region" title="CCN-504" name="L3 SF Cache Access" description="Counts the number of cache accesses. This is the first time access, and is high priority."/>
69 <event event="0x0403" option_set="HN-F_Region" title="CCN-504" name="Cache Fill" description="Counts the total allocations in the HN L3 cache, and all cache line allocations to the L3 cache."/>
70 <event event="0x0404" option_set="HN-F_Region" title="CCN-504" name="POCQ Retry" description="Counts the number of requests that have been retried."/>
71 <event event="0x0405" option_set="HN-F_Region" title="CCN-504" name="POCQ Reqs Recvd" description="Counts the number of requests received by HN."/>
72 <event event="0x0406" option_set="HN-F_Region" title="CCN-504" name="SF Hit" description="Counts the number of snoop filter hits."/>
73 <event event="0x0407" option_set="HN-F_Region" title="CCN-504" name="SF Evictions" description="Counts the number of snoop filter evictions. Cache invalidations are initiated."/>
74 <event event="0x0408" option_set="HN-F_Region" title="CCN-504" name="Snoops Sent" description="Counts the number of snoops sent. Does not differentiate between broadcast or directed snoops."/>
75 <event event="0x0409" option_set="HN-F_Region" title="CCN-504" name="Snoops Broadcast" description="Counts the number of snoop broadcasts sent."/>
76 <event event="0x040A" option_set="HN-F_Region" title="CCN-504" name="L3 Eviction" description="Counts the number of L3 evictions."/>
77 <event event="0x040B" option_set="HN-F_Region" title="CCN-504" name="L3 Fill Invalid Way" description="Counts the number of L3 fills to an invalid way."/>
78 <event event="0x040C" option_set="HN-F_Region" title="CCN-504" name="MC Retries" description="Counts the number of transactions retried by the memory controller."/>
79 <event event="0x040D" option_set="HN-F_Region" title="CCN-504" name="MC Reqs" description="Counts the number of requests to the memory controller."/>
80 <event event="0x040E" option_set="HN-F_Region" title="CCN-504" name="QOS HH Retry" description="Counts the number of times a highest-priority QoS class was retried at the HN-F."/>
81 <option_set name="RN-I_Region">
82 <option event_delta="0x800000" name="RN-I 0" description="I/O-coherent Requesting Node 0"/>
83 <option event_delta="0x820000" name="RN-I 2" description="I/O-coherent Requesting Node 2"/>
84 <option event_delta="0x860000" name="RN-I 6" description="I/O-coherent Requesting Node 6"/>
85 <option event_delta="0x8C0000" name="RN-I 12" description="I/O-coherent Requesting Node 12"/>
86 <option event_delta="0x900000" name="RN-I 16" description="I/O-coherent Requesting Node 16"/>
87 <option event_delta="0x940000" name="RN-I 20" description="I/O-coherent Requesting Node 20"/>
88 </option_set>
89 <event event="0x1601" option_set="RN-I_Region" title="CCN-504" name="S0 RDataBeats" description="S0 RDataBeats."/>
90 <event event="0x1602" option_set="RN-I_Region" title="CCN-504" name="S1 RDataBeats" description="S1 RDataBeats."/>
91 <event event="0x1603" option_set="RN-I_Region" title="CCN-504" name="S2 RDataBeats" description="S2 RDataBeats."/>
92 <event event="0x1604" option_set="RN-I_Region" title="CCN-504" name="RXDAT Flits received" description="RXDAT Flits received."/>
93 <event event="0x1605" option_set="RN-I_Region" title="CCN-504" name="TXDAT Flits sent" description="TXDAT Flits sent."/>
94 <event event="0x1606" option_set="RN-I_Region" title="CCN-504" name="Total TXREQ Flits sent" description="Total TXREQ Flits sent."/>
95 <event event="0x1607" option_set="RN-I_Region" title="CCN-504" name="Retried TXREQ Flits sent" description="Retried TXREQ Flits sent."/>
96 <event event="0x1608" option_set="RN-I_Region" title="CCN-504" name="RRT full" description="RRT full."/>
97 <event event="0x1609" option_set="RN-I_Region" title="CCN-504" name="WRT full" description="WRT full."/>
98 <event event="0x160A" option_set="RN-I_Region" title="CCN-504" name="Replayed TXREQ Flits" description="Replayed TXREQ Flits."/>
99 <option_set name="SBAS_Region">
100 <option event_delta="0x810000" name="SBAS 1" description="ACE master to CHI protocol bridge 1"/>
101 <option event_delta="0x890000" name="SBAS 9" description="ACE master to CHI protocol bridge 9"/>
102 <option event_delta="0x8B0000" name="SBAS 11" description="ACE master to CHI protocol bridge 11"/>
103 <option event_delta="0x930000" name="SBAS 19" description="ACE master to CHI protocol bridge 19"/>
104 </option_set>
105 <event event="0x1001" option_set="SBAS_Region" title="CCN-504" name="S0 RDataBeats" description="S0 RDataBeats."/>
106 <event event="0x1004" option_set="SBAS_Region" title="CCN-504" name="RXDAT Flits received" description="RXDAT Flits received."/>
107 <event event="0x1005" option_set="SBAS_Region" title="CCN-504" name="TXDAT Flits sent" description="TXDAT Flits sent."/>
108 <event event="0x1006" option_set="SBAS_Region" title="CCN-504" name="Total TXREQ Flits sent" description="Total TXREQ Flits sent."/>
109 <event event="0x1007" option_set="SBAS_Region" title="CCN-504" name="Retried TXREQ Flits sent" description="Retried TXREQ Flits sent."/>
110 <event event="0x1008" option_set="SBAS_Region" title="CCN-504" name="RRT full" description="RRT full."/>
111 <event event="0x1009" option_set="SBAS_Region" title="CCN-504" name="WRT full" description="WRT full."/>
112 <event event="0x100A" option_set="SBAS_Region" title="CCN-504" name="Replayed TXREQ Flits" description="Replayed TXREQ Flits."/>
113 </category>
diff --git a/tools/gator/daemon/events-Cortex-A12.xml b/tools/gator/daemon/events-Cortex-A12.xml
new file mode 100644
index 00000000000..9c04354ad13
--- /dev/null
+++ b/tools/gator/daemon/events-Cortex-A12.xml
@@ -0,0 +1,86 @@
1 <counter_set name="ARMv7_Cortex_A12_cnt" count="6"/>
2 <category name="Cortex-A12" counter_set="ARMv7_Cortex_A12_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="ARMv7_Cortex_A12_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
4 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
5 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
6 <event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/>
7 <event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
8 <event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
9 <event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/>
10 <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
11 <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
12 <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
13 <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
14 <event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
15 <event event="0x13" title="Memory" name="Memory access" description="Data memory access"/>
16 <event event="0x14" title="Cache" name="L1 inst access" description="Instruction cache access"/>
17 <event event="0x15" title="Cache" name="L1 data write" description="Level 1 data cache Write-Back"/>
18 <event event="0x16" title="Cache" name="L2 data access" description="Level 2 data cache access"/>
19 <event event="0x17" title="Cache" name="L2 data refill" description="Level 2 data cache refill"/>
20 <event event="0x18" title="Cache" name="L2 data write" description="Level 2 data cache Write-Back"/>
21 <event event="0x19" title="Bus" name="Access" description="Bus - Access"/>
22 <event event="0x1b" title="Instruction" name="Speculative" description="Instruction speculatively executed"/>
23 <event event="0x1c" title="Memory" name="Translation table" description="Write to translation table base architecturally executed"/>
24 <event event="0x1d" title="Bus" name="Cycle" description="Bus - Cycle"/>
25 <event event="0x40" title="Cache" name="L1 data read" description="Level 1 data cache access - Read"/>
26 <event event="0x41" title="Cache" name="L1 data access write" description="Level 1 data cache access - Write"/>
27 <event event="0x50" title="Cache" name="L2 data read" description="Level 2 data cache access - Read"/>
28 <event event="0x51" title="Cache" name="L2 data access write" description="Level 2 data cache access - Write"/>
29 <event event="0x56" title="Cache" name="L2 data victim" description="Level 2 data cache Write-Back - Victim"/>
30 <event event="0x57" title="Cache" name="L2 data clean" description="Level 2 data cache Write-Back - Cleaning and coherency"/>
31 <event event="0x58" title="Cache" name="L2 data invalidate" description="Level 2 data cache invalidate"/>
32 <event event="0x60" title="Bus" name="Read" description="Bus access - Read"/>
33 <event event="0x62" title="Bus" name="Access shared" description="Bus access - Normal"/>
34 <event event="0x63" title="Bus" name="Access not shared" description="Bus access - Not normal"/>
35 <event event="0x64" title="Bus" name="Access normal" description="Bus access - Normal"/>
36 <event event="0x65" title="Bus" name="Peripheral" description="Bus access - Peripheral"/>
37 <event event="0x66" title="Memory" name="Read" description="Data memory access - Read"/>
38 <event event="0x67" title="Memory" name="Write" description="Data memory access - Write"/>
39 <event event="0x68" title="Memory" name="Unaligned Read" description="Unaligned access - Read"/>
40 <event event="0x69" title="Memory" name="Unaligned Write" description="Unaligned access - Write"/>
41 <event event="0x6a" title="Memory" name="Unaligned" description="Unaligned access"/>
42 <event event="0x6c" title="Intrinsic" name="LDREX" description="Exclusive instruction speculatively executed - LDREX"/>
43 <event event="0x6e" title="Intrinsic" name="STREX fail" description="Exclusive instruction speculatively executed - STREX fail"/>
44 <event event="0x6f" title="Intrinsic" name="STREX" description="Exclusive instruction speculatively executed - STREX"/>
45 <event event="0x70" title="Instruction" name="Load" description="Instruction speculatively executed - Load"/>
46 <event event="0x71" title="Instruction" name="Store" description="Instruction speculatively executed - Store"/>
47 <event event="0x72" title="Instruction" name="Load/Store" description="Instruction speculatively executed - Load or store"/>
48 <event event="0x73" title="Instruction" name="Integer" description="Instruction speculatively executed - Integer data processing"/>
49 <event event="0x74" title="Instruction" name="Advanced SIMD" description="Instruction speculatively executed - Advanced SIMD"/>
50 <event event="0x75" title="Instruction" name="VFP" description="Instruction speculatively executed - VFP"/>
51 <event event="0x76" title="Instruction" name="Software change" description="Instruction speculatively executed - Software change of the PC"/>
52 <event event="0x78" title="Instruction" name="Immediate branch" description="Branch speculatively executed - Immediate branch"/>
53 <event event="0x79" title="Instruction" name="Procedure return" description="Branch speculatively executed - Procedure return"/>
54 <event event="0x7a" title="Instruction" name="Indirect branch" description="Branch speculatively executed - Indirect branch"/>
55 <event event="0x7c" title="Instruction" name="ISB" description="Barrier speculatively executed - ISB"/>
56 <event event="0x7d" title="Instruction" name="DSB" description="Barrier speculatively executed - DSB"/>
57 <event event="0x7e" title="Instruction" name="DMB" description="Barrier speculatively executed - DMB"/>
58 <event event="0x81" title="Exception" name="Undefined" description="Exception taken, other synchronous"/>
59 <event event="0x8a" title="Exception" name="Hypervisor call" description="Exception taken, Hypervisor Call"/>
60 <event event="0xc0" title="Instruction" name="Stalled Linefill" description="Instruction side stalled due to a Linefill"/>
61 <event event="0xc1" title="Instruction" name="Stalled Page Table Walk" description="Instruction Side stalled due to a Page Table Walk"/>
62 <event event="0xc2" title="Cache" name="4 Ways Read" description="Number of set of 4 ways read in the instruction cache - Tag RAM"/>
63 <event event="0xc3" title="Cache" name="Ways Read" description="Number of ways read in the instruction cache - Data RAM"/>
64 <event event="0xc4" title="Cache" name="BATC Read" description="Number of ways read in the instruction BTAC RAM"/>
65 <event event="0xca" title="Memory" name="Snoop" description="Data snooped from other processor. This event counts memory-read operations that read data from another processor within the local Cortex-A12 cluster, rather than accessing the L2 cache or issuing an external read. It increments on each transaction, rather than on each beat of data"/>
66 <event event="0xd3" title="Slots" name="Load-Store Unit" description="Duration during which all slots in the Load-Store Unit are busy"/>
67 <event event="0xd8" title="Slots" name="Load-Store Issue Queue" description="Duration during which all slots in the Load-Store Issue queue are busy"/>
68 <event event="0xd9" title="Slots" name="Data Processing Issue Queue" description="Duration during which all slots in the Data Processing issue queue are busy"/>
69 <event event="0xda" title="Slots" name="Data Engine Issue Queue" description="Duration during which all slots in the Data Engine issue queue are busy"/>
70 <event event="0xdb" title="NEON" name="Flush" description="Number of NEON instruction which fail their condition code and lead to a flush of the DE pipe"/>
71 <event event="0xdc" title="Hypervisor" name="Traps" description="Number of Trap to hypervisor"/>
72 <event event="0xde" title="PTM" name="EXTOUT 0" description="PTM EXTOUT 0"/>
73 <event event="0xdf" title="PTM" name="EXTOUT 1" description="PTM EXTOUT 1"/>
74 <event event="0xe0" title="MMU" name="Table Walk" description="Duration during which the MMU handle a Page table walk"/>
75 <event event="0xe1" title="MMU" name="Stage1 Table Walk" description="Duration during which the MMU handle a Stage1 Page table walk"/>
76 <event event="0xe2" title="MMU" name="Stage2 Table Walk" description="Duration during which the MMU handle a Stage2 Page table walk"/>
77 <event event="0xe3" title="MMU" name="LSU Table Walk" description="Duration during which the MMU handle a Page table walk requested by the Load Store Unit"/>
78 <event event="0xe4" title="MMU" name="Instruction Table Walk" description="Duration during which the MMU handle a Page table walk requested by the Instruction side"/>
79 <event event="0xe5" title="MMU" name="Preload Table Walk" description="Duration during which the MMU handle a Page table walk requested by a Preload instruction or Prefetch request"/>
80 <event event="0xe6" title="MMU" name="cp15 Table Walk" description="Duration during which the MMU handle a Page table walk requested by a cp15 operation (maintenance by MVA and VA-to-PA operation)"/>
81 <event event="0xe7" title="Cache" name="L1 PLD TLB refill" description="Level 1 PLD TLB refill"/>
82 <event event="0xe8" title="Cache" name="L1 CP15 TLB refill" description="Level 1 CP15 TLB refill"/>
83 <event event="0xe9" title="Cache" name="L1 TLB flush" description="Level 1 TLB flush"/>
84 <event event="0xea" title="Cache" name="L2 TLB access" description="Level 2 TLB access"/>
85 <event event="0xeb" title="Cache" name="L2 TLB miss" description="Level 2 TLB miss"/>
86 </category>
diff --git a/tools/gator/daemon/events-Cortex-A15.xml b/tools/gator/daemon/events-Cortex-A15.xml
new file mode 100644
index 00000000000..f50e55d6619
--- /dev/null
+++ b/tools/gator/daemon/events-Cortex-A15.xml
@@ -0,0 +1,68 @@
1 <counter_set name="ARMv7_Cortex_A15_cnt" count="6"/>
2 <category name="Cortex-A15" counter_set="ARMv7_Cortex_A15_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="ARMv7_Cortex_A15_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Software" name="Increment" description="Software increment architecturally executed"/>
5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
7 <event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/>
8 <event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
9 <event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
10 <event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/>
11 <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
12 <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
13 <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
14 <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
15 <event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
16 <event event="0x13" title="Memory" name="Memory access" description="Data memory access"/>
17 <event event="0x14" title="Cache" name="L1 inst access" description="Instruction cache access"/>
18 <event event="0x15" title="Cache" name="L1 data write" description="Level 1 data cache Write-Back"/>
19 <event event="0x16" title="Cache" name="L2 data access" description="Level 2 data cache access"/>
20 <event event="0x17" title="Cache" name="L2 data refill" description="Level 2 data cache refill"/>
21 <event event="0x18" title="Cache" name="L2 data write" description="Level 2 data cache Write-Back"/>
22 <event event="0x19" title="Bus" name="Access" description="Bus - Access"/>
23 <event event="0x1a" title="Memory" name="Error" description="Local memory error"/>
24 <event event="0x1b" title="Instruction" name="Speculative" description="Instruction speculatively executed"/>
25 <event event="0x1c" title="Memory" name="Translation table" description="Write to translation table base architecturally executed"/>
26 <event event="0x1d" title="Bus" name="Cycle" description="Bus - Cycle"/>
27 <event event="0x40" title="Cache" name="L1 data read" description="Level 1 data cache access - Read"/>
28 <event event="0x41" title="Cache" name="L1 data access write" description="Level 1 data cache access - Write"/>
29 <event event="0x42" title="Cache" name="L1 data refill read" description="Level 1 data cache refill - Read"/>
30 <event event="0x43" title="Cache" name="L1 data refill write" description="Level 1 data cache refill - Write"/>
31 <event event="0x46" title="Cache" name="L1 data victim" description="Level 1 data cache Write-Back - Victim"/>
32 <event event="0x47" title="Cache" name="L1 data clean" description="Level 1 data cache Write-Back - Cleaning and coherency"/>
33 <event event="0x48" title="Cache" name="L1 data invalidate" description="Level 1 data cache invalidate"/>
34 <event event="0x4c" title="TLB" name="L1 data refill read" description="Level 1 data TLB refill - Read"/>
35 <event event="0x4d" title="TLB" name="L1 data refill write" description="Level 1 data TLB refill - Write"/>
36 <event event="0x50" title="Cache" name="L2 data read" description="Level 2 data cache access - Read"/>
37 <event event="0x51" title="Cache" name="L2 data access write" description="Level 2 data cache access - Write"/>
38 <event event="0x52" title="Cache" name="L2 data refill read" description="Level 2 data cache refill - Read"/>
39 <event event="0x53" title="Cache" name="L2 data refill write" description="Level 2 data cache refill - Write"/>
40 <event event="0x56" title="Cache" name="L2 data victim" description="Level 2 data cache Write-Back - Victim"/>
41 <event event="0x57" title="Cache" name="L2 data clean" description="Level 2 data cache Write-Back - Cleaning and coherency"/>
42 <event event="0x58" title="Cache" name="L2 data invalidate" description="Level 2 data cache invalidate"/>
43 <event event="0x60" title="Bus" name="Read" description="Bus access - Read"/>
44 <event event="0x61" title="Bus" name="Write" description="Bus access - Write"/>
45 <event event="0x64" title="Bus" name="Access normal" description="Bus access - Normal"/>
46 <event event="0x65" title="Bus" name="Peripheral" description="Bus access - Peripheral"/>
47 <event event="0x66" title="Memory" name="Read" description="Data memory access - Read"/>
48 <event event="0x67" title="Memory" name="Write" description="Data memory access - Write"/>
49 <event event="0x68" title="Memory" name="Unaligned Read" description="Unaligned access - Read"/>
50 <event event="0x69" title="Memory" name="Unaligned Write" description="Unaligned access - Write"/>
51 <event event="0x6a" title="Memory" name="Unaligned" description="Unaligned access"/>
52 <event event="0x6c" title="Intrinsic" name="LDREX" description="Exclusive instruction speculatively executed - LDREX"/>
53 <event event="0x6d" title="Intrinsic" name="STREX pass" description="Exclusive instruction speculatively executed - STREX pass"/>
54 <event event="0x6e" title="Intrinsic" name="STREX fail" description="Exclusive instruction speculatively executed - STREX fail"/>
55 <event event="0x70" title="Instruction" name="Load" description="Instruction speculatively executed - Load"/>
56 <event event="0x71" title="Instruction" name="Store" description="Instruction speculatively executed - Store"/>
57 <event event="0x72" title="Instruction" name="Load/Store" description="Instruction speculatively executed - Load or store"/>
58 <event event="0x73" title="Instruction" name="Integer" description="Instruction speculatively executed - Integer data processing"/>
59 <event event="0x74" title="Instruction" name="Advanced SIMD" description="Instruction speculatively executed - Advanced SIMD"/>
60 <event event="0x75" title="Instruction" name="VFP" description="Instruction speculatively executed - VFP"/>
61 <event event="0x76" title="Instruction" name="Software change" description="Instruction speculatively executed - Software change of the PC"/>
62 <event event="0x78" title="Instruction" name="Immediate branch" description="Branch speculatively executed - Immediate branch"/>
63 <event event="0x79" title="Instruction" name="Procedure return" description="Branch speculatively executed - Procedure return"/>
64 <event event="0x7a" title="Instruction" name="Indirect branch" description="Branch speculatively executed - Indirect branch"/>
65 <event event="0x7c" title="Instruction" name="ISB" description="Barrier speculatively executed - ISB"/>
66 <event event="0x7d" title="Instruction" name="DSB" description="Barrier speculatively executed - DSB"/>
67 <event event="0x7e" title="Instruction" name="DMB" description="Barrier speculatively executed - DMB"/>
68 </category>
diff --git a/tools/gator/daemon/events-Cortex-A5.xml b/tools/gator/daemon/events-Cortex-A5.xml
new file mode 100644
index 00000000000..d67581d77c0
--- /dev/null
+++ b/tools/gator/daemon/events-Cortex-A5.xml
@@ -0,0 +1,36 @@
1 <counter_set name="ARMv7_Cortex_A5_cnt" count="2"/>
2 <category name="Cortex-A5" counter_set="ARMv7_Cortex_A5_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="ARMv7_Cortex_A5_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
7 <event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/>
8 <event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
9 <event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
10 <event event="0x06" title="Instruction" name="Memory read" description="Memory-reading instruction architecturally executed"/>
11 <event event="0x07" title="Instruction" name="Memory write" description="Memory-writing instruction architecturally executed"/>
12 <event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/>
13 <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
14 <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
15 <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
16 <event event="0x0c" title="Branch" name="PC change" description="Software change of the Program Counter, except by an exception, architecturally executed"/>
17 <event event="0x0d" title="Branch" name="Immediate" description="Immediate branch architecturally executed"/>
18 <event event="0x0e" title="Procedure" name="Return" description="Procedure return, other than exception return, architecturally executed"/>
19 <event event="0x0f" title="Memory" name="Unaligned access" description="Unaligned access architecturally executed"/>
20 <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
21 <event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
22 <event event="0x13" title="Memory" name="Memory access" description="Data memory access"/>
23 <event event="0x14" title="Cache" name="Instruction access" description="Instruction cache access"/>
24 <event event="0x15" title="Cache" name="Data eviction" description="Data cache eviction"/>
25 <event event="0x86" title="Interrupts" name="IRQ" description="IRQ exception taken"/>
26 <event event="0x87" title="Interrupts" name="FIQ" description="FIQ exception taken"/>
27 <event event="0xC0" title="Memory" name="External request" description="External memory request"/>
28 <event event="0xC1" title="Memory" name="Non-cacheable ext req" description="Non-cacheable external memory request"/>
29 <event event="0xC2" title="Cache" name="Linefill" description="Linefill because of prefetch"/>
30 <event event="0xC3" title="Cache" name="Linefill dropped" description="Prefetch linefill dropped"/>
31 <event event="0xC4" title="Cache" name="Allocate mode enter" description="Entering read allocate mode"/>
32 <event event="0xC5" title="Cache" name="Allocate mode" description="Read allocate mode"/>
33 <event event="0xC7" title="ETM" name="ETM Ext Out[0]" description="ETM - ETM Ext Out[0]"/>
34 <event event="0xC8" title="ETM" name="ETM Ext Out[1]" description="ETM - ETM Ext Out[1]"/>
35 <event event="0xC9" title="Instruction" name="Pipeline stall" description="Data Write operation that stalls the pipeline because the store buffer is full"/>
36 </category>
diff --git a/tools/gator/daemon/events-Cortex-A53.xml b/tools/gator/daemon/events-Cortex-A53.xml
new file mode 100644
index 00000000000..5ba17907d5a
--- /dev/null
+++ b/tools/gator/daemon/events-Cortex-A53.xml
@@ -0,0 +1,87 @@
1 <counter_set name="ARM_Cortex-A53_cnt" count="6"/>
2 <category name="Cortex-A53" counter_set="ARM_Cortex-A53_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="ARM_Cortex-A53_ccnt" event="0x11" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
7 <event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/>
8 <event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
9 <event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
10 <event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/>
11 <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
12 <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
13 <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
14 <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
15 <event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
16 <event event="0x13" title="Memory" name="Memory access" description="Data memory access"/>
17 <event event="0x14" title="Cache" name="L1 inst access" description="Level 1 instruction cache access"/>
18 <event event="0x15" title="Cache" name="L1 data write" description="Level 1 data cache Write-Back"/>
19 <event event="0x16" title="Cache" name="L2 data access" description="Level 2 data cache access"/>
20 <event event="0x17" title="Cache" name="L2 data refill" description="Level 2 data cache refill"/>
21 <event event="0x18" title="Cache" name="L2 data write" description="Level 2 data cache Write-Back"/>
22 <event event="0x19" title="Bus" name="Access" description="Bus access"/>
23 <event event="0x1A" title="Memory" name="Error" description="Local memory error"/>
24 <event event="0x1B" title="Instruction" name="Speculative" description="Operation speculatively executed"/>
25 <event event="0x1C" title="Memory" name="Translation table" description="Instruction architecturally executed (condition check pass) - Write to translation table base"/>
26 <event event="0x1D" title="Bus" name="Cycle" description="Bus cycle"/>
27 <event event="0x1E" title="Counter chain" name="Odd Performance" description="Odd performance counter chain mode"/>
28 <event event="0x40" title="Cache" name="L1 data read" description="Level 1 data cache access - Read"/>
29 <event event="0x41" title="Cache" name="L1 data access write" description="Level 1 data cache access - Write"/>
30 <event event="0x42" title="Cache" name="L1 data refill read" description="Level 1 data cache refill - Read"/>
31 <event event="0x43" title="Cache" name="L1 data refill write" description="Level 1 data cache refill - Write"/>
32 <event event="0x46" title="Cache" name="L1 data victim" description="Level 1 data cache Write-back - Victim"/>
33 <event event="0x47" title="Cache" name="L1 data clean" description="Level 1 data cache Write-back - Cleaning and coherency"/>
34 <event event="0x48" title="Cache" name="L1 data invalidate" description="Level 1 data cache invalidate"/>
35 <event event="0x4C" title="Cache" name="L1 data refill read" description="Level 1 data TLB refill - Read"/>
36 <event event="0x4D" title="Cache" name="L1 data refill write" description="Level 1 data TLB refill - Write"/>
37 <event event="0x50" title="Cache" name="L2 data read" description="Level 2 data cache access - Read"/>
38 <event event="0x51" title="Cache" name="L2 data access write" description="Level 2 data cache access - Write"/>
39 <event event="0x52" title="Cache" name="L2 data refill read" description="Level 2 data cache refill - Read"/>
40 <event event="0x53" title="Cache" name="L2 data refill write" description="Level 2 data cache refill - Write"/>
41 <event event="0x56" title="Cache" name="L2 data victim" description="Level 2 data cache Write-back - Victim"/>
42 <event event="0x57" title="Cache" name="L2 data clean" description="Level 2 data cache Write-back - Cleaning and coherency"/>
43 <event event="0x58" title="Cache" name="L2 data invalidate" description="Level 2 data cache invalidate"/>
44 <event event="0x60" title="Bus" name="Read" description="Bus access - Read"/>
45 <event event="0x61" title="Bus" name="Write" description="Bus access - Write"/>
46 <event event="0x62" title="Bus" name="Access shared" description="Bus access - Normal"/>
47 <event event="0x63" title="Bus" name="Access not shared" description="Bus access - Not normal"/>
48 <event event="0x64" title="Bus" name="Access normal" description="Bus access - Normal"/>
49 <event event="0x65" title="Bus" name="Peripheral" description="Bus access - Peripheral"/>
50 <event event="0x66" title="Memory" name="Read" description="Data memory access - Read"/>
51 <event event="0x67" title="Memory" name="Write" description="Data memory access - Write"/>
52 <event event="0x68" title="Memory" name="Unaligned Read" description="Unaligned access - Read"/>
53 <event event="0x69" title="Memory" name="Unaligned Write" description="Unaligned access - Write"/>
54 <event event="0x6A" title="Memory" name="Unaligned" description="Unaligned access"/>
55 <event event="0x6C" title="Intrinsic" name="LDREX" description="Exclusive operation speculatively executed - LDREX"/>
56 <event event="0x6D" title="Intrinsic" name="STREX pass" description="Exclusive instruction speculatively executed - STREX pass"/>
57 <event event="0x6E" title="Intrinsic" name="STREX fail" description="Exclusive operation speculatively executed - STREX fail"/>
58 <event event="0x70" title="Instruction" name="Load" description="Operation speculatively executed - Load"/>
59 <event event="0x71" title="Instruction" name="Store" description="Operation speculatively executed - Store"/>
60 <event event="0x72" title="Instruction" name="Load/Store" description="Operation speculatively executed - Load or store"/>
61 <event event="0x73" title="Instruction" name="Integer" description="Operation speculatively executed - Integer data processing"/>
62 <event event="0x74" title="Instruction" name="Advanced SIMD" description="Operation speculatively executed - Advanced SIMD"/>
63 <event event="0x75" title="Instruction" name="VFP" description="Operation speculatively executed - VFP"/>
64 <event event="0x76" title="Instruction" name="Software change" description="Operation speculatively executed - Software change of the PC"/>
65 <event event="0x77" title="Instruction" name="Crypto" description="Operation speculatively executed, crypto data processing"/>
66 <event event="0x78" title="Instruction" name="Immediate branch" description="Branch speculatively executed - Immediate branch"/>
67 <event event="0x79" title="Instruction" name="Procedure return" description="Branch speculatively executed - Procedure return"/>
68 <event event="0x7A" title="Instruction" name="Indirect branch" description="Branch speculatively executed - Indirect branch"/>
69 <event event="0x7C" title="Instruction" name="ISB" description="Barrier speculatively executed - ISB"/>
70 <event event="0x7D" title="Instruction" name="DSB" description="Barrier speculatively executed - DSB"/>
71 <event event="0x7E" title="Instruction" name="DMB" description="Barrier speculatively executed - DMB"/>
72 <event event="0x81" title="Exception" name="Undefined" description="Exception taken, other synchronous"/>
73 <event event="0x82" title="Exception" name="Supervisor" description="Exception taken, Supervisor Call"/>
74 <event event="0x83" title="Exception" name="Instruction abort" description="Exception taken, Instruction Abort"/>
75 <event event="0x84" title="Exception" name="Data abort" description="Exception taken, Data Abort or SError"/>
76 <event event="0x86" title="Interrupts" name="IRQ" description="Exception taken, IRQ"/>
77 <event event="0x87" title="Interrupts" name="FIQ" description="Exception taken, FIQ"/>
78 <event event="0x88" title="Exception" name="Secure monitor call" description="Exception taken, Secure Monitor Call"/>
79 <event event="0x8A" title="Exception" name="Hypervisor call" description="Exception taken, Hypervisor Call"/>
80 <event event="0x8B" title="Exception" name="Instruction abort non-local" description="Exception taken, Instruction Abort not taken locally"/>
81 <event event="0x8C" title="Exception" name="Data abort non-local" description="Exception taken, Data Abort or SError not taken locally"/>
82 <event event="0x8D" title="Exception" name="Other non-local" description="Exception taken - Other traps not taken locally"/>
83 <event event="0x8E" title="Exception" name="IRQ non-local" description="Exception taken, IRQ not taken locally"/>
84 <event event="0x8F" title="Exception" name="FIQ non-local" description="Exception taken, FIQ not taken locally"/>
85 <event event="0x90" title="Release Consistency" name="Load" description="Release consistency instruction speculatively executed - Load Acquire"/>
86 <event event="0x91" title="Release Consistency" name="Store" description="Release consistency instruction speculatively executed - Store Release"/>
87 </category>
diff --git a/tools/gator/daemon/events-Cortex-A57.xml b/tools/gator/daemon/events-Cortex-A57.xml
new file mode 100644
index 00000000000..fbe96c2d4eb
--- /dev/null
+++ b/tools/gator/daemon/events-Cortex-A57.xml
@@ -0,0 +1,87 @@
1 <counter_set name="ARM_Cortex-A57_cnt" count="6"/>
2 <category name="Cortex-A57" counter_set="ARM_Cortex-A57_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="ARM_Cortex-A57_ccnt" event="0x11" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
7 <event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/>
8 <event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
9 <event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
10 <event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/>
11 <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
12 <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
13 <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
14 <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
15 <event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
16 <event event="0x13" title="Memory" name="Memory access" description="Data memory access"/>
17 <event event="0x14" title="Cache" name="L1 inst access" description="Level 1 instruction cache access"/>
18 <event event="0x15" title="Cache" name="L1 data write" description="Level 1 data cache Write-Back"/>
19 <event event="0x16" title="Cache" name="L2 data access" description="Level 2 data cache access"/>
20 <event event="0x17" title="Cache" name="L2 data refill" description="Level 2 data cache refill"/>
21 <event event="0x18" title="Cache" name="L2 data write" description="Level 2 data cache Write-Back"/>
22 <event event="0x19" title="Bus" name="Access" description="Bus access"/>
23 <event event="0x1A" title="Memory" name="Error" description="Local memory error"/>
24 <event event="0x1B" title="Instruction" name="Speculative" description="Operation speculatively executed"/>
25 <event event="0x1C" title="Memory" name="Translation table" description="Instruction architecturally executed (condition check pass) - Write to translation table base"/>
26 <event event="0x1D" title="Bus" name="Cycle" description="Bus cycle"/>
27 <event event="0x1E" title="Counter chain" name="Odd Performance" description="Odd performance counter chain mode"/>
28 <event event="0x40" title="Cache" name="L1 data read" description="Level 1 data cache access - Read"/>
29 <event event="0x41" title="Cache" name="L1 data access write" description="Level 1 data cache access - Write"/>
30 <event event="0x42" title="Cache" name="L1 data refill read" description="Level 1 data cache refill - Read"/>
31 <event event="0x43" title="Cache" name="L1 data refill write" description="Level 1 data cache refill - Write"/>
32 <event event="0x46" title="Cache" name="L1 data victim" description="Level 1 data cache Write-back - Victim"/>
33 <event event="0x47" title="Cache" name="L1 data clean" description="Level 1 data cache Write-back - Cleaning and coherency"/>
34 <event event="0x48" title="Cache" name="L1 data invalidate" description="Level 1 data cache invalidate"/>
35 <event event="0x4C" title="Cache" name="L1 data refill read" description="Level 1 data TLB refill - Read"/>
36 <event event="0x4D" title="Cache" name="L1 data refill write" description="Level 1 data TLB refill - Write"/>
37 <event event="0x50" title="Cache" name="L2 data read" description="Level 2 data cache access - Read"/>
38 <event event="0x51" title="Cache" name="L2 data access write" description="Level 2 data cache access - Write"/>
39 <event event="0x52" title="Cache" name="L2 data refill read" description="Level 2 data cache refill - Read"/>
40 <event event="0x53" title="Cache" name="L2 data refill write" description="Level 2 data cache refill - Write"/>
41 <event event="0x56" title="Cache" name="L2 data victim" description="Level 2 data cache Write-back - Victim"/>
42 <event event="0x57" title="Cache" name="L2 data clean" description="Level 2 data cache Write-back - Cleaning and coherency"/>
43 <event event="0x58" title="Cache" name="L2 data invalidate" description="Level 2 data cache invalidate"/>
44 <event event="0x60" title="Bus" name="Read" description="Bus access - Read"/>
45 <event event="0x61" title="Bus" name="Write" description="Bus access - Write"/>
46 <event event="0x62" title="Bus" name="Access shared" description="Bus access - Normal"/>
47 <event event="0x63" title="Bus" name="Access not shared" description="Bus access - Not normal"/>
48 <event event="0x64" title="Bus" name="Access normal" description="Bus access - Normal"/>
49 <event event="0x65" title="Bus" name="Peripheral" description="Bus access - Peripheral"/>
50 <event event="0x66" title="Memory" name="Read" description="Data memory access - Read"/>
51 <event event="0x67" title="Memory" name="Write" description="Data memory access - Write"/>
52 <event event="0x68" title="Memory" name="Unaligned Read" description="Unaligned access - Read"/>
53 <event event="0x69" title="Memory" name="Unaligned Write" description="Unaligned access - Write"/>
54 <event event="0x6A" title="Memory" name="Unaligned" description="Unaligned access"/>
55 <event event="0x6C" title="Intrinsic" name="LDREX" description="Exclusive operation speculatively executed - LDREX"/>
56 <event event="0x6D" title="Intrinsic" name="STREX pass" description="Exclusive instruction speculatively executed - STREX pass"/>
57 <event event="0x6E" title="Intrinsic" name="STREX fail" description="Exclusive operation speculatively executed - STREX fail"/>
58 <event event="0x70" title="Instruction" name="Load" description="Operation speculatively executed - Load"/>
59 <event event="0x71" title="Instruction" name="Store" description="Operation speculatively executed - Store"/>
60 <event event="0x72" title="Instruction" name="Load/Store" description="Operation speculatively executed - Load or store"/>
61 <event event="0x73" title="Instruction" name="Integer" description="Operation speculatively executed - Integer data processing"/>
62 <event event="0x74" title="Instruction" name="Advanced SIMD" description="Operation speculatively executed - Advanced SIMD"/>
63 <event event="0x75" title="Instruction" name="VFP" description="Operation speculatively executed - VFP"/>
64 <event event="0x76" title="Instruction" name="Software change" description="Operation speculatively executed - Software change of the PC"/>
65 <event event="0x77" title="Instruction" name="Crypto" description="Operation speculatively executed, crypto data processing"/>
66 <event event="0x78" title="Instruction" name="Immediate branch" description="Branch speculatively executed - Immediate branch"/>
67 <event event="0x79" title="Instruction" name="Procedure return" description="Branch speculatively executed - Procedure return"/>
68 <event event="0x7A" title="Instruction" name="Indirect branch" description="Branch speculatively executed - Indirect branch"/>
69 <event event="0x7C" title="Instruction" name="ISB" description="Barrier speculatively executed - ISB"/>
70 <event event="0x7D" title="Instruction" name="DSB" description="Barrier speculatively executed - DSB"/>
71 <event event="0x7E" title="Instruction" name="DMB" description="Barrier speculatively executed - DMB"/>
72 <event event="0x81" title="Exception" name="Undefined" description="Exception taken, other synchronous"/>
73 <event event="0x82" title="Exception" name="Supervisor" description="Exception taken, Supervisor Call"/>
74 <event event="0x83" title="Exception" name="Instruction abort" description="Exception taken, Instruction Abort"/>
75 <event event="0x84" title="Exception" name="Data abort" description="Exception taken, Data Abort or SError"/>
76 <event event="0x86" title="Interrupts" name="IRQ" description="Exception taken, IRQ"/>
77 <event event="0x87" title="Interrupts" name="FIQ" description="Exception taken, FIQ"/>
78 <event event="0x88" title="Exception" name="Secure monitor call" description="Exception taken, Secure Monitor Call"/>
79 <event event="0x8A" title="Exception" name="Hypervisor call" description="Exception taken, Hypervisor Call"/>
80 <event event="0x8B" title="Exception" name="Instruction abort non-local" description="Exception taken, Instruction Abort not taken locally"/>
81 <event event="0x8C" title="Exception" name="Data abort non-local" description="Exception taken, Data Abort or SError not taken locally"/>
82 <event event="0x8D" title="Exception" name="Other non-local" description="Exception taken - Other traps not taken locally"/>
83 <event event="0x8E" title="Exception" name="IRQ non-local" description="Exception taken, IRQ not taken locally"/>
84 <event event="0x8F" title="Exception" name="FIQ non-local" description="Exception taken, FIQ not taken locally"/>
85 <event event="0x90" title="Release Consistency" name="Load" description="Release consistency instruction speculatively executed - Load Acquire"/>
86 <event event="0x91" title="Release Consistency" name="Store" description="Release consistency instruction speculatively executed - Store Release"/>
87 </category>
diff --git a/tools/gator/daemon/events-Cortex-A7.xml b/tools/gator/daemon/events-Cortex-A7.xml
new file mode 100644
index 00000000000..6e078b3cffa
--- /dev/null
+++ b/tools/gator/daemon/events-Cortex-A7.xml
@@ -0,0 +1,43 @@
1 <counter_set name="ARMv7_Cortex_A7_cnt" count="4"/>
2 <category name="Cortex-A7" counter_set="ARMv7_Cortex_A7_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="ARMv7_Cortex_A7_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Software" name="Increment" description="Software increment architecturally executed"/>
5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
7 <event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/>
8 <event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
9 <event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
10 <event event="0x06" title="Memory" name="Data Read" description="Data read architecturally executed"/>
11 <event event="0x07" title="Memory" name="Data Write" description="Data write architecturally executed"/>
12 <event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/>
13 <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
14 <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
15 <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
16 <event event="0x0c" title="Branch" name="PC change" description="Software change of the Program Counter, except by an exception, architecturally executed"/>
17 <event event="0x0d" title="Branch" name="Immediate" description="Immediate branch architecturally executed"/>
18 <event event="0x0f" title="Memory" name="Unaligned access" description="Unaligned access architecturally executed"/>
19 <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
20 <event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
21 <event event="0x13" title="Memory" name="Memory access" description="Data memory access"/>
22 <event event="0x14" title="Cache" name="L1 inst access" description="Instruction cache access"/>
23 <event event="0x15" title="Cache" name="L1 data eviction" description="Level 1 data cache eviction"/>
24 <event event="0x16" title="Cache" name="L2 data access" description="Level 2 data cache access"/>
25 <event event="0x17" title="Cache" name="L2 data refill" description="Level 2 data cache refill"/>
26 <event event="0x18" title="Cache" name="L2 data write" description="Level 2 data cache Write-Back"/>
27 <event event="0x19" title="Bus" name="Access" description="Bus - Access"/>
28 <event event="0x1d" title="Bus" name="Cycle" description="Bus - Cycle"/>
29 <event event="0x60" title="Bus" name="Read" description="Bus access - Read"/>
30 <event event="0x61" title="Bus" name="Write" description="Bus access - Write"/>
31 <event event="0x86" title="Exception" name="IRQ" description="IRQ exception taken"/>
32 <event event="0x87" title="Exception" name="FIQ" description="FIQ exception taken"/>
33 <event event="0xC0" title="Memory" name="External request" description="External memory request"/>
34 <event event="0xC1" title="Memory" name="Non-cacheable ext req" description="Non-cacheable external memory request"/>
35 <event event="0xC2" title="Cache" name="Linefill" description="Linefill because of prefetch"/>
36 <event event="0xC3" title="Cache" name="Linefill dropped" description="Prefetch linefill dropped"/>
37 <event event="0xC4" title="Cache" name="Allocate mode enter" description="Entering read allocate mode"/>
38 <event event="0xC5" title="Cache" name="Allocate mode" description="Read allocate mode"/>
39 <event event="0xC7" title="ETM" name="ETM Ext Out[0]" description="ETM - ETM Ext Out[0]"/>
40 <event event="0xC8" title="ETM" name="ETM Ext Out[1]" description="ETM - ETM Ext Out[1]"/>
41 <event event="0xC9" title="Instruction" name="Pipeline stall" description="Data Write operation that stalls the pipeline because the store buffer is full"/>
42 <event event="0xCA" title="Memory" name="Snoop" description="Data snooped from other processor. This event counts memory-read operations that read data from another processor within the local cluster, rather than accessing the L2 cache or issuing an external read."/>
43 </category>
diff --git a/tools/gator/daemon/events-Cortex-A8.xml b/tools/gator/daemon/events-Cortex-A8.xml
new file mode 100644
index 00000000000..a69e25ab2c3
--- /dev/null
+++ b/tools/gator/daemon/events-Cortex-A8.xml
@@ -0,0 +1,52 @@
1 <counter_set name="ARMv7_Cortex_A8_cnt" count="4"/>
2 <category name="Cortex-A8" counter_set="ARMv7_Cortex_A8_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="ARMv7_Cortex_A8_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
7 <event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/>
8 <event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
9 <event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
10 <event event="0x06" title="Instruction" name="Memory read" description="Memory-reading instruction architecturally executed"/>
11 <event event="0x07" title="Instruction" name="Memory write" description="Memory-writing instruction architecturally executed"/>
12 <event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/>
13 <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
14 <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
15 <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
16 <event event="0x0c" title="Branch" name="PC change" description="Software change of the Program Counter, except by an exception, architecturally executed"/>
17 <event event="0x0d" title="Branch" name="Immediate" description="Immediate branch architecturally executed"/>
18 <event event="0x0e" title="Procedure" name="Return" description="Procedure return, other than exception return, architecturally executed"/>
19 <event event="0x0f" title="Memory" name="Unaligned access" description="Unaligned access architecturally executed"/>
20 <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
21 <event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
22 <event event="0x40" title="Cache" name="Write buffer full" description="Any write buffer full cycle"/>
23 <event event="0x41" title="Cache" name="L2 store" description="Any store that is merged in the L2 memory system"/>
24 <event event="0x42" title="Cache" name="Bufferable transaction" description="Any bufferable store transaction from load/store to L2 cache, excluding eviction or cast out data"/>
25 <event event="0x43" title="Cache" name="L2 access" description="Any accesses to the L2 cache"/>
26 <event event="0x44" title="Cache" name="L2 miss" description="Any cacheable miss in the L2 cache"/>
27 <event event="0x45" title="AXI" name="Read" description="The number of AXI read data transfers"/>
28 <event event="0x46" title="AXI" name="Write" description="The number of AXI write data transfers"/>
29 <event event="0x47" title="Memory" name="Replay event" description="Any replay event in the memory system"/>
30 <event event="0x48" title="Memory" name="Unaligned access replay" description="Any unaligned memory access that results in a replay"/>
31 <event event="0x49" title="Cache" name="L1 data hash miss" description="Any L1 data memory access that misses in the cache as a result of the hashing algorithm"/>
32 <event event="0x4a" title="Cache" name="L1 inst hash miss" description="Any L1 instruction memory access that misses in the cache as a result of the hashing algorithm"/>
33 <event event="0x4b" title="Cache" name="L1 page coloring" description="Any L1 data memory access in which a page coloring alias occurs"/>
34 <event event="0x4c" title="NEON" name="L1 cache hit" description="Any NEON access that hits in the L1 data cache"/>
35 <event event="0x4d" title="NEON" name="L1 cache access" description="Any NEON cacheable data accesses for L1 data cache"/>
36 <event event="0x4e" title="NEON" name="L2 cache access" description="Any L2 cache accesses as a result of a NEON memory access"/>
37 <event event="0x4f" title="NEON" name="L2 cache hit" description="Any NEON hit in the L2 cache"/>
38 <event event="0x50" title="Cache" name="L1 inst access" description="Any L1 instruction cache access, excluding CP15 cache accesses"/>
39 <event event="0x51" title="Branch" name="Return stack misprediction" description="Any return stack misprediction because of incorrect target address for a taken return stack pop"/>
40 <event event="0x52" title="Branch" name="Direction misprediction" description="Branch direction misprediction"/>
41 <event event="0x53" title="Branch" name="Taken prediction" description="Any predictable branch that is predicted to be taken"/>
42 <event event="0x54" title="Branch" name="Executed and taken prediction" description="Any predictable branch that is executed and taken"/>
43 <event event="0x55" title="Core" name="Operations issued" description="Number of operations issued, where an operation is either: an instruction or one operation in a sequence of operations that make up a multi-cycle instruction"/>
44 <event event="0x56" title="Core" name="No issue cycles" description="Increment for every cycle that no instructions are available for issue"/>
45 <event event="0x57" title="Core" name="Issue cycles" description="For every cycle, this event counts the number of instructions issued in that cycle. Multi-cycle instructions are only counted once"/>
46 <event event="0x58" title="NEON" name="MRC data wait" description="Number of cycles the processor stalls waiting on MRC data from NEON"/>
47 <event event="0x59" title="NEON" name="Full queue" description="Number of cycles that the processor stalls as a result of a full NEON instruction queue or NEON load queue"/>
48 <event event="0x5a" title="NEON" name="Idle" description="Number of cycles that NEON and integer processors are both not idle"/>
49 <event event="0x70" title="External" name="PMUEXTIN[0]" description="Counts any event from external input source PMUEXTIN[0]"/>
50 <event event="0x71" title="External" name="PMUEXTIN[1]" description="Counts any event from external input source PMUEXTIN[1]"/>
51 <event event="0x72" title="External" name="PMUEXTIN[0,1]" description="Counts any event from both external input sources PMUEXTIN[0] and PMUEXTIN[1]"/>
52 </category>
diff --git a/tools/gator/daemon/events-Cortex-A9.xml b/tools/gator/daemon/events-Cortex-A9.xml
new file mode 100644
index 00000000000..3e7f8289062
--- /dev/null
+++ b/tools/gator/daemon/events-Cortex-A9.xml
@@ -0,0 +1,65 @@
1 <counter_set name="ARMv7_Cortex_A9_cnt" count="6"/>
2 <category name="Cortex-A9" counter_set="ARMv7_Cortex_A9_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="ARMv7_Cortex_A9_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
7 <event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/>
8 <event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
9 <event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
10 <event event="0x06" title="Instruction" name="Memory read" description="Memory-reading instruction architecturally executed"/>
11 <event event="0x07" title="Instruction" name="Memory write" description="Memory-writing instruction architecturally executed"/>
12 <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
13 <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
14 <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
15 <event event="0x0c" title="Branch" name="PC change" description="Software change of the Program Counter, except by an exception, architecturally executed"/>
16 <event event="0x0d" title="Branch" name="Immediate" description="Immediate branch architecturally executed"/>
17 <event event="0x0f" title="Memory" name="Unaligned access" description="Unaligned access architecturally executed"/>
18 <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
19 <event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
20 <event event="0x40" title="Java" name="Bytecode execute" description="Counts the number of Java bytecodes being decoded, including speculative ones"/>
21 <event event="0x41" title="Java" name="SW bytecode execute" description="Counts the number of software java bytecodes being decoded, including speculative ones"/>
22 <event event="0x42" title="Jazelle" name="Backward branch execute" description="Counts the number of Jazelle taken branches being executed"/>
23 <event event="0x50" title="Cache" name="Coherency miss" description="Counts the number of coherent linefill requests performed by the Cortex-A9 processor which also miss in all the other Cortex-A9 processors, meaning that the request is sent to the external memory"/>
24 <event event="0x51" title="Cache" name="Coherency hit" description="Counts the number of coherent linefill requests performed by the Cortex-A9 processor which hit in another Cortex-A9 processor, meaning that the linefill data is fetched directly from the relevant Cortex-A9 cache"/>
25 <event event="0x60" title="Cache" name="Inst dependent stall" description="Counts the number of cycles where the processor is ready to accept new instructions, but does not receive any because of the instruction side not being able to provide any and the instruction cache is currently performing at least one linefill"/>
26 <event event="0x61" title="Cache" name="Data dependent stall" description="Counts the number of cycles where the core has some instructions that it cannot issue to any pipeline, and the Load Store unit has at least one pending linefill request, and no pending TLB requests"/>
27 <event event="0x62" title="Cache" name="TLB stall" description="Counts the number of cycles where the processor is stalled waiting for the completion of translation table walks from the main TLB"/>
28 <event event="0x63" title="Intrinsic" name="STREX pass" description="Counts the number of STREX instructions architecturally executed and passed"/>
29 <event event="0x64" title="Intrinsic" name="STREX fail" description="Counts the number of STREX instructions architecturally executed and failed"/>
30 <event event="0x65" title="Cache" name="Data eviction" description="Counts the number of eviction requests because of a linefill in the data cache"/>
31 <event event="0x66" title="Pipeline" name="Issue stage no dispatch" description="Counts the number of cycles where the issue stage does not dispatch any instruction because it is empty or cannot dispatch any instructions"/>
32 <event event="0x67" title="Pipeline" name="Issue stage empty" description="Counts the number of cycles where the issue stage is empty"/>
33 <event event="0x68" title="Instruction" name="Executed" description="Counts the number of instructions going through the Register Renaming stage. This number is an approximate number of the total number of instructions speculatively executed, and even more approximate of the total number of instructions architecturally executed"/>
34 <event event="0x69" title="Cache" name="Data linefills" description="Counts the number of linefills performed on the external AXI bus"/>
35 <event event="0x6A" title="Cache" name="Prefetch linefills" description="Counts the number of data linefills caused by prefetcher requests"/>
36 <event event="0x6B" title="Cache" name="Prefetch hits" description="Counts the number of cache hits in a line that belongs to a stream followed by the prefetcher"/>
37 <event event="0x6E" title="Core" name="Functions" description="Counts the number of procedure returns whose condition codes do not fail, excluding all returns from exception"/>
38 <event event="0x70" title="Instruction" name="Main execution unit" description="Counts the number of instructions being executed in the main execution pipeline of the processor, the multiply pipeline and arithmetic logic unit pipeline"/>
39 <event event="0x71" title="Instruction" name="Second execution unit" description="Counts the number of instructions being executed in the processor second execution pipeline (ALU)"/>
40 <event event="0x72" title="Instruction" name="Load/Store" description="Counts the number of instructions being executed in the Load/Store unit"/>
41 <event event="0x73" title="Instruction" name="Floating point" description="Counts the number of Floating-point instructions going through the Register Rename stage"/>
42 <event event="0x74" title="Instruction" name="NEON" description="Counts the number of NEON instructions going through the Register Rename stage"/>
43 <event event="0x80" title="Stalls" name="PLD" description="Counts the number of cycles where the processor is stalled because PLD slots are all full"/>
44 <event event="0x81" title="Stalls" name="Memory write" description="Counts the number of cycles when the processor is stalled and the data side is stalled too because it is full and executing writes to the external memory"/>
45 <event event="0x82" title="Stalls" name="Inst main TLB miss" description="Counts the number of stall cycles because of main TLB misses on requests issued by the instruction side"/>
46 <event event="0x83" title="Stalls" name="Data main TLB miss" description="Counts the number of stall cycles because of main TLB misses on requests issued by the data side"/>
47 <event event="0x84" title="Stalls" name="Inst micro TLB miss" description="Counts the number of stall cycles because of micro TLB misses on the instruction side"/>
48 <event event="0x85" title="Stalls" name="Data micro TLB miss" description="Counts the number of stall cycles because of micro TLB misses on the data side"/>
49 <event event="0x86" title="Stalls" name="DMB" description="Counts the number of stall cycles because of the execution of a DMB memory barrier"/>
50 <event event="0x8A" title="Clock" name="Integer core" description="Counts the number of cycles during which the integer core clock is enabled"/>
51 <event event="0x8B" title="Clock" name="Data engine" description="Counts the number of cycles during which the Data Engine clock is enabled"/>
52 <event event="0x8C" title="Clock" name="NEON" description="Counts the number of cycles when the NEON SIMD clock is enabled"/>
53 <event event="0x8D" title="Memory" name="TLB inst allocations" description="Counts the number of TLB allocations because of Instruction requests"/>
54 <event event="0x8E" title="Memory" name="TLB data allocations" description="Counts the number of TLB allocations because of Data requests"/>
55 <event event="0x90" title="Instruction" name="ISB" description="Counts the number of ISB instructions architecturally executed"/>
56 <event event="0x91" title="Instruction" name="DSB" description="Counts the number of DSB instructions architecturally executed"/>
57 <event event="0x92" title="Instruction" name="DMB" description="Counts the number of DMB instructions speculatively executed"/>
58 <event event="0x93" title="External" name="Interrupts" description="Counts the number of external interrupts executed by the processor"/>
59 <event event="0xA0" title="PLE" name="Cache line rq completed" description="Counts the number of PLE cache line requests completed"/>
60 <event event="0xA1" title="PLE" name="Cache line rq skipped" description="Counts the number of PLE cache line requests skipped"/>
61 <event event="0xA2" title="PLE" name="FIFO flush" description="Counts the number of PLE FIFO flush requests"/>
62 <event event="0xA3" title="PLE" name="Request completed" description="Counts the number of PLE FIFO flush completed"/>
63 <event event="0xA4" title="PLE" name="FIFO overflow" description="Counts the number of PLE FIFO flush overflowed"/>
64 <event event="0xA5" title="PLE" name="Request programmed" description="Counts the number of PLE FIFO flush program requests"/>
65 </category>
diff --git a/tools/gator/daemon/events-Filesystem.xml b/tools/gator/daemon/events-Filesystem.xml
new file mode 100644
index 00000000000..5feeb9014a6
--- /dev/null
+++ b/tools/gator/daemon/events-Filesystem.xml
@@ -0,0 +1,11 @@
1 <category name="Filesystem">
2 <!-- counter attributes must be unique -->
3 <!-- regex item in () is the value shown -->
4 <!-- these counters are not compatible with userspace gator, i.e. gator.ko must be loaded -->
5 <!--
6 <event counter="/sys/devices/system/cpu/cpu1/online" title="online" name="cpu 1" class="absolute" description="If cpu 1 is online"/>
7 <event counter="/proc/self/loginuid" title="loginuid" name="loginuid" class="absolute" description="loginuid"/>
8 <event counter="/proc/self/stat" title="stat" name="rss" class="absolute" regex="-?[0-9]+ \(.*\) . -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+ (-?[0-9]+)" units="pages" description="resident set size"/>
9 <event counter="/proc/stat" title="proc-stat" name="processes" class="absolute" regex="processes ([0-9]+)" description="Number of processes and threads created"/>
10 -->
11 </category>
diff --git a/tools/gator/daemon/events-Krait-architected.xml b/tools/gator/daemon/events-Krait-architected.xml
new file mode 100644
index 00000000000..b8d3bcb48de
--- /dev/null
+++ b/tools/gator/daemon/events-Krait-architected.xml
@@ -0,0 +1,22 @@
1 <counter_set name="Krait_cnt" count="4"/>
2 <category name="Krait" counter_set="Krait_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="Krait_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
7 <event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/>
8 <event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
9 <event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
10 <event event="0x06" title="Instruction" name="Memory read" description="Memory-reading instruction architecturally executed"/>
11 <event event="0x07" title="Instruction" name="Memory write" description="Memory-writing instruction architecturally executed"/>
12 <event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/>
13 <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
14 <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
15 <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
16 <event event="0x0c" title="Program Counter" name="SW change" description="Software change of PC, except by an exception, architecturally executed"/>
17 <event event="0x0d" title="Branch" name="Immediate" description="Immediate branch architecturally executed"/>
18 <event event="0x0e" title="Branch" name="Procedure Return" description="Procedure return architecturally executed (not by exceptions)"/>
19 <event event="0x0f" title="Memory" name="Unaligned access" description="Unaligned access architecturally executed"/>
20 <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
21 <event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
22 </category>
diff --git a/tools/gator/daemon/events-L2C-310.xml b/tools/gator/daemon/events-L2C-310.xml
new file mode 100644
index 00000000000..923fb90334d
--- /dev/null
+++ b/tools/gator/daemon/events-L2C-310.xml
@@ -0,0 +1,18 @@
1 <counter_set name="L2C-310_cnt" count="2"/>
2 <category name="L2C-310" counter_set="L2C-310_cnt" per_cpu="no">
3 <event event="0x1" title="L2 Cache" name="CastOUT" description="Eviction, CastOUT, of a line from the L2 cache"/>
4 <event event="0x2" title="L2 Cache" name="Data Read Hit" description="Data read hit in the L2 cache"/>
5 <event event="0x3" title="L2 Cache" name="Data Read Request" description="Data read lookup to the L2 cache. Subsequently results in a hit or miss"/>
6 <event event="0x4" title="L2 Cache" name="Data Write Hit" description="Data write hit in the L2 cache"/>
7 <event event="0x5" title="L2 Cache" name="Data Write Request" description="Data write lookup to the L2 cache. Subsequently results in a hit or miss"/>
8 <event event="0x6" title="L2 Cache" name="Data Write-Through Request" description="Data write lookup to the L2 cache with Write-Through attribute. Subsequently results in a hit or miss"/>
9 <event event="0x7" title="L2 Cache" name="Instruction Read Hit" description="Instruction read hit in the L2 cache"/>
10 <event event="0x8" title="L2 Cache" name="Instruction Read Request" description="Instruction read lookup to the L2 cache. Subsequently results in a hit or miss"/>
11 <event event="0x9" title="L2 Cache" name="Write Allocate Miss" description="Allocation into the L2 cache caused by a write, with Write-Allocate attribute, miss"/>
12 <event event="0xa" title="L2 Cache" name="Internal Prefetch Allocate" description="Allocation of a prefetch generated by L2C-310 into the L2 cache"/>
13 <event event="0xb" title="L2 Cache" name="Prefitch Hit" description="Prefetch hint hits in the L2 cache"/>
14 <event event="0xc" title="L2 Cache" name="Prefitch Allocate" description="Prefetch hint allocated into the L2 cache"/>
15 <event event="0xd" title="L2 Cache" name="Speculative Read Received" description="Speculative read received"/>
16 <event event="0xe" title="L2 Cache" name="Speculative Read Confirmed" description="Speculative read confirmed"/>
17 <event event="0xf" title="L2 Cache" name="Prefetch Hint Received" description="Prefetch hint received"/>
18 </category>
diff --git a/tools/gator/daemon/events-Linux.xml b/tools/gator/daemon/events-Linux.xml
new file mode 100644
index 00000000000..c306dd62208
--- /dev/null
+++ b/tools/gator/daemon/events-Linux.xml
@@ -0,0 +1,16 @@
1 <category name="Linux">
2 <event counter="Linux_irq_softirq" title="Interrupts" name="SoftIRQ" per_cpu="yes" description="Linux SoftIRQ taken"/>
3 <event counter="Linux_irq_irq" title="Interrupts" name="IRQ" per_cpu="yes" description="Linux IRQ taken"/>
4 <event counter="Linux_block_rq_wr" title="Disk IO" name="Write" units="B" description="Disk IO Bytes Written"/>
5 <event counter="Linux_block_rq_rd" title="Disk IO" name="Read" units="B" description="Disk IO Bytes Read"/>
6 <event counter="Linux_net_rx" title="Network" name="Receive" units="B" description="Receive network traffic, including effect from Streamline"/>
7 <event counter="Linux_net_tx" title="Network" name="Transmit" units="B" description="Transmit network traffic, including effect from Streamline"/>
8 <event counter="Linux_sched_switch" title="Scheduler" name="Switch" per_cpu="yes" description="Context switch events"/>
9 <event counter="Linux_meminfo_memused" title="Memory" name="Used" class="absolute" units="B" proc="yes" description="Total used memory size. Note: a process' used memory includes shared memory that may be counted more than once (equivalent to RES from top). Kernel threads are not filterable."/>
10 <event counter="Linux_meminfo_memfree" title="Memory" name="Free" class="absolute" display="minimum" units="B" description="Available memory size"/>
11 <event counter="Linux_meminfo_bufferram" title="Memory" name="Buffer" class="absolute" units="B" description="Memory used by OS disk buffers"/>
12 <event counter="Linux_power_cpu_freq" title="Clock" name="Frequency" per_cpu="yes" class="absolute" units="Hz" series_composition="overlay" average_cores="yes" description="Frequency setting of the CPU"/>
13 <event counter="Linux_power_cpu_idle" title="Idle" name="State" per_cpu="yes" class="absolute" description="CPU Idle State + 1, set the Sample Rate to None to prevent the hrtimer from interrupting the system"/>
14 <event counter="Linux_cpu_wait_contention" title="CPU Contention" name="Wait" per_cpu="no" class="activity" derived="yes" rendering_type="bar" average_selection="yes" percentage="yes" modifier="10000" color="0x003c96fb" description="Thread waiting on contended resource"/>
15 <event counter="Linux_cpu_wait_io" title="CPU I/O" name="Wait" per_cpu="no" class="activity" derived="yes" rendering_type="bar" average_selection="yes" percentage="yes" modifier="10000" color="0x00b30000" description="Thread waiting on I/O resource"/>
16 </category>
diff --git a/tools/gator/daemon/events-Mali-4xx.xml b/tools/gator/daemon/events-Mali-4xx.xml
new file mode 100644
index 00000000000..0a95dfeb648
--- /dev/null
+++ b/tools/gator/daemon/events-Mali-4xx.xml
@@ -0,0 +1,245 @@
1 <counter_set name="ARM_Mali-4xx_VP_0_cnt" count="2"/>
2 <counter_set name="ARM_Mali-4xx_SW_cnt" count="0"/>
3 <category name="Mali Vertex Processor" counter_set="ARM_Mali-4xx_VP_0_cnt" per_cpu="no">
4 <event event="0x01" title="Mali-4xx VP" name="Active cycles" description="Number of cycles per frame the MaliGP2 was active."/>
5 <event event="0x02" title="Mali-4xx VP" name="Active cycles, vertex shader" description="Number of cycles per frame the vertex shader unit was active."/>
6 <event event="0x03" title="Mali-4xx VP" name="Active cycles, vertex storer" description="Number of cycles per frame the vertex storer unit was active."/>
7 <event event="0x04" title="Mali-4xx VP" name="Active cycles, vertex loader" description="Number of cycles per frame the vertex loader unit was active."/>
8 <event event="0x05" title="Mali-4xx VP" name="Cycles vertex loader waiting for vertex shader" description="Number of cycles per frame the vertex loader was idle while waiting on the vertex shader."/>
9 <event event="0x06" title="Mali-4xx VP" name="Words read, system bus" description="Total number of 64 bit words read by the GP2 from the system bus per frame."/>
10 <event event="0x07" title="Mali-4xx VP" name="Words written, system bus" description="Total number of 64 bit words written by the GP2 to the system bus per frame."/>
11 <event event="0x08" title="Mali-4xx VP" name="Read bursts, system bus" description="Number of read bursts by the GP2 from the system bus per frame."/>
12 <event event="0x09" title="Mali-4xx VP" name="Write bursts, system bus" description="Number of write bursts from the MaliGP2 to the system bus per frame."/>
13 <event event="0x0a" title="Mali-4xx VP" name="Vertices processed" description="Number of vertices processed by the MaliGP2 per frame."/>
14 <event event="0x0b" title="Mali-4xx VP" name="Vertices fetched" description="Number of vertices fetched by the MaliGP2 per frame."/>
15 <event event="0x0c" title="Mali-4xx VP" name="Primitives fetched" description="Number of graphics primitives fetched by the MaliGP2 per frame."/>
16 <event event="0x0e" title="Mali-4xx VP" name="Primitives culled" description="Number of graphics primitives discarded per frame, because they were seen from the back or were offscreen."/>
17 <event event="0x0f" title="Mali-4xx VP" name="Commands written to tiles" description="Number of commands (8 Bytes, mainly primitives) written by GP2 to the PP input data structure per frame."/>
18 <event event="0x10" title="Mali-4xx VP" name="Memory blocks allocated" description="Number of overflow data blocks needed for outputting the PP input data structure per frame ."/>
19 <event event="0x13" title="Mali-4xx VP" name="Vertex loader cache misses" description="Number of cache misses for the vertex shader's vertex input unit per frame."/>
20 <event event="0x16" title="Mali-4xx VP" name="Active cycles, vertex shader command processor" description="Number of cycles per frame the GP2 vertex shader command processor was active. This includes time waiting for semaphores."/>
21 <event event="0x17" title="Mali-4xx VP" name="Active cycles, PLBU command processor" description="Number of cycles per frame the MaliGP2 PLBU command processor was active. This includes time waiting for semaphores."/>
22 <event event="0x18" title="Mali-4xx VP" name="Active Cycles, PLBU list writer" description="Number of cycles per frame the MaliGP2 PLBU output unit was active. This includes time spent waiting on the bus."/>
23 <event event="0x19" title="Mali-4xx VP" name="Active cycles, PLBU geometry processing" description="Number of cycles per frame the MaliGP2 PLBU was active, excepting final data output. In other words: active cycles through the prepare list commands. This includes time spent waiting on the bus."/>
24 <event event="0x1b" title="Mali-4xx VP" name="Active cycles, PLBU primitive assembly" description="Number of active cycles per frame spent by the MaliGP2 PLBU doing primitive assembly. This does not include scissoring or final output. This includes time spent waiting on the bus."/>
25 <event event="0x1c" title="Mali-4xx VP" name="Active cycles, PLBU vertex fetcher" description="Number of active cycles per frame spent by the MaliGP2 PLBU fetching vertex data. This includes time spent waiting on the bus."/>
26 <event event="0x1e" title="Mali-4xx VP" name="Active cycles, Bounding-box and command generator" description="Number of active cycles per frame spent by the MaliGP2 PLBU setting up bounding boxes and commands (mainly graphics primitives). This includes time spent waiting on the bus."/>
27 <event event="0x20" title="Mali-4xx VP" name="Active cycles, Scissor tile iterator" description="Number of active cycles per frame spent by the MaliGP2 PLBU iterating over tiles to perform scissoring. This includes time spent waiting on the bus."/>
28 <event event="0x21" title="Mali-4xx VP" name="Active cycles, PLBU tile iterator" description="Number of active cycles per frame spent by the MaliGP2 PLBU iterating over the tiles in the bounding box generating commands (mainly graphics primitives). This includes time spent waiting on the bus."/>
29 </category>
30 <category name="Mali Fragment Processor" per_cpu="no">
31 <counter_set name="ARM_Mali-4xx_FP_0_cnt" title="Mali-4xx FP0" description="Mali GPU Fragment Processor 0" count="2"/>
32 <counter_set name="ARM_Mali-4xx_FP_1_cnt" title="Mali-4xx FP1" description="Mali GPU Fragment Processor 1" count="2"/>
33 <counter_set name="ARM_Mali-4xx_FP_2_cnt" title="Mali-4xx FP2" description="Mali GPU Fragment Processor 2" count="2"/>
34 <counter_set name="ARM_Mali-4xx_FP_3_cnt" title="Mali-4xx FP3" description="Mali GPU Fragment Processor 3" count="2"/>
35 <counter_set name="ARM_Mali-4xx_FP_4_cnt" title="Mali-4xx FP4" description="Mali GPU Fragment Processor 4" count="2"/>
36 <counter_set name="ARM_Mali-4xx_FP_5_cnt" title="Mali-4xx FP5" description="Mali GPU Fragment Processor 5" count="2"/>
37 <counter_set name="ARM_Mali-4xx_FP_6_cnt" title="Mali-4xx FP6" description="Mali GPU Fragment Processor 6" count="2"/>
38 <counter_set name="ARM_Mali-4xx_FP_7_cnt" title="Mali-4xx FP7" description="Mali GPU Fragment Processor 7" count="2"/>
39 <event event="0x00" title="Mali-4xx FP" name="Active clock cycles" description="Active clock cycles, between polygon start and IRQ."/>
40 <event event="0x02" title="Mali-4xx FP" name="Total bus reads" description="Total number of 64-bit words read from the bus."/>
41 <event event="0x03" title="Mali-4xx FP" name="Total bus writes" description="Total number of 64-bit words written to the bus."/>
42 <event event="0x04" title="Mali-4xx FP" name="Bus read request cycles" description="Number of cycles during which the bus read request signal was HIGH."/>
43 <event event="0x05" title="Mali-4xx FP" name="Bus write request cycles" description="Number of cycles during which the bus write request signal was HIGH."/>
44 <event event="0x06" title="Mali-4xx FP" name="Bus read transactions count" description="Number of read requests accepted by the bus."/>
45 <event event="0x07" title="Mali-4xx FP" name="Bus write transactions" description="Number of write requests accepted by the bus."/>
46 <event event="0x09" title="Mali-4xx FP" name="Tile writeback writes" description="64-bit words written to the bus by the writeback unit."/>
47 <event event="0x0a" title="Mali-4xx FP" name="Store unit writes" description="64-bit words written to the bus by the store unit."/>
48 <event event="0x0d" title="Mali-4xx FP" name="Texture cache uncompressed reads" description="Number of 64-bit words read from the bus into the uncompressed textures cache."/>
49 <event event="0x0e" title="Mali-4xx FP" name="Polygon list reads" description="Number of 64-bit words read from the bus by the polygon list reader."/>
50 <event event="0x0f" title="Mali-4xx FP" name="RSW reads" description="Number of 64-bit words read from the bus into the Render State Word register."/>
51 <event event="0x10" title="Mali-4xx FP" name="Vertex cache reads" description="Number of 64-bit words read from the bus into the vertex cache."/>
52 <event event="0x11" title="Mali-4xx FP" name="Uniform remapping reads" description="Number of 64-bit words read from the bus when reading from the uniform remapping table."/>
53 <event event="0x12" title="Mali-4xx FP" name="Program cache reads" description="Number of 64-bit words read from the bus into the fragment shader program cache."/>
54 <event event="0x13" title="Mali-4xx FP" name="Varying reads" description="Number of 64-bit words containing varyings generated by the vertex processing read from the bus."/>
55 <event event="0x14" title="Mali-4xx FP" name="Texture descriptors reads" description="Number of 64-bit words containing texture descriptors read from the bus."/>
56 <event event="0x15" title="Mali-4xx FP" name="Texture descriptor remapping reads" description="Number of 64-bit words read from the bus when reading from the texture descriptor remapping table."/>
57 <event event="0x17" title="Mali-4xx FP" name="Load unit reads" description="Number of 64-bit words read from the bus by the LOAD sub-instruction."/>
58 <event event="0x18" title="Mali-4xx FP" name="Polygon count" description="Number of triangles read from the polygon list."/>
59 <event event="0x19" title="Mali-4xx FP" name="Pixel rectangle count" description="Number of pixel rectangles read from the polygon list."/>
60 <event event="0x1a" title="Mali-4xx FP" name="Lines count" description="Number of lines read from the polygon list."/>
61 <event event="0x1b" title="Mali-4xx FP" name="Points count" description="Number of points read from the polygon list."/>
62 <event event="0x1c" title="Mali-4xx FP" name="Stall cycles PolygonListReader" description="Number of clock cycles the Polygon List Reader waited for output being collected."/>
63 <event event="0x1d" title="Mali-4xx FP" name="Stall cycles triangle setup" description="Number of clock cycles the TSC waited for input."/>
64 <event event="0x1e" title="Mali-4xx FP" name="Quad rasterized count" description="Number of 2x?2 quads output from rasterizer."/>
65 <event event="0x1f" title="Mali-4xx FP" name="Fragment rasterized count" description="Number of fragment rasterized. Fragments/(Quads*4) gives average actual fragments per quad."/>
66 <event event="0x20" title="Mali-4xx FP" name="Fragment rejected fragment-kill count" description="Number of fragments exiting the fragment shader as killed."/>
67 <event event="0x21" title="Mali-4xx FP" name="Fragment rejected fwd-fragment-kill count" description="Number of fragments killed by forward fragment kill."/>
68 <event event="0x22" title="Mali-4xx FP" name="Fragment passed z/stencil count" description="Number of fragments passing Z and stencil test."/>
69 <event event="0x23" title="Mali-4xx FP" name="Patches rejected early z/stencil count" description="Number of patches rejected by EarlyZ. A patch can be 8x8, 4x4 or 2x2 pixels."/>
70 <event event="0x24" title="Mali-4xx FP" name="Patches evaluated" description="Number of patches evaluated for EarlyZ rejection."/>
71 <event event="0x25" title="Mali-4xx FP" name="Instruction completed count" description="Number of fragment shader instruction words completed. It is a function of pixels processed and the length of the shader programs."/>
72 <event event="0x26" title="Mali-4xx FP" name="Instruction failed rendezvous count" description="Number of fragment shader instructions not completed because of failed Rendezvous."/>
73 <event event="0x27" title="Mali-4xx FP" name="Instruction failed varying-miss count" description="Number of fragment shader instructions not completed because of failed varying operation."/>
74 <event event="0x28" title="Mali-4xx FP" name="Instruction failed texture-miss count" description="Number of fragment shader instructions not completed because of failed texture operation."/>
75 <event event="0x29" title="Mali-4xx FP" name="Instruction failed load-miss count" description="Number of fragment shader instructions not completed because of failed load operation."/>
76 <event event="0x2a" title="Mali-4xx FP" name="Instruction failed tile read-miss count" description="Number of fragment shader instructions not completed because of failed read from the tilebuffer."/>
77 <event event="0x2b" title="Mali-4xx FP" name="Instruction failed store-miss count" description="Number of fragment shader instructions not completed because of failed store operation."/>
78 <event event="0x2c" title="Mali-4xx FP" name="Rendezvous breakage count" description="Number of Rendezvous breakages reported."/>
79 <event event="0x2d" title="Mali-4xx FP" name="Pipeline bubbles cycle count" description="Number of unused cycles in the fragment shader while rendering is active."/>
80 <event event="0x2e" title="Mali-4xx FP" name="Texture mapper multipass count" description="Number of texture operations looped because of more texture passes needed."/>
81 <event event="0x2f" title="Mali-4xx FP" name="Texture mapper cycle count" description="Number of texture operation cycles."/>
82 <event event="0x30" title="Mali-4xx FP" name="Vertex cache hit count" description="Number of times a requested vertex was found in the cache (Number of vertex cache hits)."/>
83 <event event="0x31" title="Mali-4xx FP" name="Vertex cache miss count" description="Number of times a requested vertex was not found in the cache (Number of vertex cache misses)."/>
84 <event event="0x32" title="Mali-4xx FP" name="Varying cache hit count" description="Number of times a requested varying was found in the cache (Number of varying cache hits)."/>
85 <event event="0x33" title="Mali-4xx FP" name="Varying cache miss count" description="Number of times a requested varying was not found in the cache (Number of varying cache misses)."/>
86 <event event="0x34" title="Mali-4xx FP" name="Varying cache conflict miss count" description="Number of times a requested varying was not in the cache and its value, retrieved from memory, must overwrite an older cache entry. This happens when an access pattern cannot be serviced by the cache."/>
87 <event event="0x35" title="Mali-4xx FP" name="Texture cache hit count" description="Number of times a requested texel was found in the texture cache (Number of texture cache hits)."/>
88 <event event="0x36" title="Mali-4xx FP" name="Texture cache miss count" description="Number of times a requested texel was not found in the texture cache (Number of texture cache misses)."/>
89 <event event="0x37" title="Mali-4xx FP" name="Texture cache conflict miss count" description="Number of times a requested texel was not in the cache and its value, retrieved from memory, must overwrite an older cache entry. This happens when an access pattern cannot be serviced by the cache."/>
90 <event event="0x38" title="Mali-4xx FP" name="Compressed texture cache hit count" description="Number of times a requested item was found in the cache."/>
91 <event event="0x39" title="Mali-4xx FP" name="Compressed texture cache miss count" description="Number of times a requested item was not found in the cache."/>
92 <event event="0x3a" title="Mali-4xx FP" name="Load/Store cache hit count" description="Number of hits in the load/store cache."/>
93 <event event="0x3b" title="Mali-4xx FP" name="Load/Store cache miss count" description="Number of misses in the load/store cache."/>
94 <event event="0x3c" title="Mali-4xx FP" name="Program cache hit count" description="Number of hits in the program cache."/>
95 <event event="0x3d" title="Mali-4xx FP" name="Program cache miss count" description="Number of misses in the program cache."/>
96 </category>
97 <counter_set name="ARM_Mali-4xx_L2_0_cnt" title="Mali-4xx L2" description="Mali GPU L2 Cache Core 0" count="2"/>
98 <category name="Mali-4xx L2" counter_set="ARM_Mali-4xx_L2_0_cnt" per_cpu="no">
99 <event event="0x01" title="Mali L2 Cache" name="Total clock cycles" description="Total clock cycles"/>
100 <event event="0x02" title="Mali L2 Cache" name="Active clock cycles" description="Active clock cycles"/>
101 <option_set name="All">
102 <option event_delta="0x08" name="Master" description="Master"/>
103 <option event_delta="0x10" name="All slaves" description="All slaves"/>
104 <option event_delta="0x20" name="Slave 0" description="Slave 0"/>
105 <option event_delta="0x30" name="Slave 1" description="Slave 1"/>
106 <option event_delta="0x40" name="Slave 2" description="Slave 2"/>
107 <option event_delta="0x50" name="Slave 3" description="Slave 3"/>
108 <option event_delta="0x60" name="Slave 4" description="Slave 4"/>
109 </option_set>
110 <option_set name="Slaves">
111 <option event_delta="0x10" name="All slaves" description="All slaves"/>
112 <option event_delta="0x20" name="Slave 0" description="Slave 0"/>
113 <option event_delta="0x30" name="Slave 1" description="Slave 1"/>
114 <option event_delta="0x40" name="Slave 2" description="Slave 2"/>
115 <option event_delta="0x50" name="Slave 3" description="Slave 3"/>
116 <option event_delta="0x60" name="Slave 4" description="Slave 4"/>
117 </option_set>
118 <event event="0x00" option_set="All" title="Mali L2 Cache" name="Read transactions" description="Read transactions"/>
119 <event event="0x01" option_set="All" title="Mali L2 Cache" name="Write transactions" description="Write transactions"/>
120 <event event="0x02" option_set="All" title="Mali L2 Cache" name="Words read" description="Words read"/>
121 <event event="0x03" option_set="All" title="Mali L2 Cache" name="Words written" description="Words written"/>
122 <event event="0x04" option_set="Slaves" title="Mali L2 Cache" name="Read hits" description="Read hits"/>
123 <event event="0x05" option_set="Slaves" title="Mali L2 Cache" name="Read misses" description="Read misses"/>
124 <event event="0x06" option_set="Slaves" title="Mali L2 Cache" name="Write invalidates" description="Write invalidates"/>
125 <event event="0x07" option_set="Slaves" title="Mali L2 Cache" name="Read invalidates" description="Read invalidates"/>
126 <event event="0x08" option_set="Slaves" title="Mali L2 Cache" name="Cacheable read transactions" description="Cacheable read transactions"/>
127 </category>
128 <counter_set name="ARM_Mali-4xx_L2_1_cnt" title="Mali-4xx L2 1" description="Mali GPU L2 Cache Core 1" count="2"/>
129 <category name="Mali-4xx L2_1" counter_set="ARM_Mali-4xx_L2_1_cnt" per_cpu="no">
130 <event event="0x01" title="Mali L2 Cache 1" name="Total clock cycles" description="Total clock cycles"/>
131 <event event="0x02" title="Mali L2 Cache 1" name="Active clock cycles" description="Active clock cycles"/>
132 <option_set name="All">
133 <option event_delta="0x08" name="Master" description="Master"/>
134 <option event_delta="0x10" name="All slaves" description="All slaves"/>
135 <option event_delta="0x20" name="Slave 0" description="Slave 0"/>
136 <option event_delta="0x30" name="Slave 1" description="Slave 1"/>
137 <option event_delta="0x40" name="Slave 2" description="Slave 2"/>
138 <option event_delta="0x50" name="Slave 3" description="Slave 3"/>
139 <option event_delta="0x60" name="Slave 4" description="Slave 4"/>
140 </option_set>
141 <option_set name="Slaves">
142 <option event_delta="0x10" name="All slaves" description="All slaves"/>
143 <option event_delta="0x20" name="Slave 0" description="Slave 0"/>
144 <option event_delta="0x30" name="Slave 1" description="Slave 1"/>
145 <option event_delta="0x40" name="Slave 2" description="Slave 2"/>
146 <option event_delta="0x50" name="Slave 3" description="Slave 3"/>
147 <option event_delta="0x60" name="Slave 4" description="Slave 4"/>
148 </option_set>
149 <event event="0x00" option_set="All" title="Mali L2 Cache 1" name="Read transactions" description="Read transactions"/>
150 <event event="0x01" option_set="All" title="Mali L2 Cache 1" name="Write transactions" description="Write transactions"/>
151 <event event="0x02" option_set="All" title="Mali L2 Cache 1" name="Words read" description="Words read"/>
152 <event event="0x03" option_set="All" title="Mali L2 Cache 1" name="Words written" description="Words written"/>
153 <event event="0x04" option_set="Slaves" title="Mali L2 Cache 1" name="Read hits" description="Read hits"/>
154 <event event="0x05" option_set="Slaves" title="Mali L2 Cache 1" name="Read misses" description="Read misses"/>
155 <event event="0x06" option_set="Slaves" title="Mali L2 Cache 1" name="Write invalidates" description="Write invalidates"/>
156 <event event="0x07" option_set="Slaves" title="Mali L2 Cache 1" name="Read invalidates" description="Read invalidates"/>
157 <event event="0x08" option_set="Slaves" title="Mali L2 Cache 1" name="Cacheable read transactions" description="Cacheable read transactions"/>
158 </category>
159 <counter_set name="ARM_Mali-4xx_L2_2_cnt" title="Mali-4xx L2 2" description="Mali GPU L2 Cache Core 2" count="2"/>
160 <category name="Mali-4xx L2_2" counter_set="ARM_Mali-4xx_L2_2_cnt" per_cpu="no">
161 <event event="0x01" title="Mali L2 Cache 2" name="Total clock cycles" description="Total clock cycles"/>
162 <event event="0x02" title="Mali L2 Cache 2" name="Active clock cycles" description="Active clock cycles"/>
163 <option_set name="All">
164 <option event_delta="0x08" name="Master" description="Master"/>
165 <option event_delta="0x10" name="All slaves" description="All slaves"/>
166 <option event_delta="0x20" name="Slave 0" description="Slave 0"/>
167 <option event_delta="0x30" name="Slave 1" description="Slave 1"/>
168 <option event_delta="0x40" name="Slave 2" description="Slave 2"/>
169 <option event_delta="0x50" name="Slave 3" description="Slave 3"/>
170 <option event_delta="0x60" name="Slave 4" description="Slave 4"/>
171 </option_set>
172 <option_set name="Slaves">
173 <option event_delta="0x10" name="All slaves" description="All slaves"/>
174 <option event_delta="0x20" name="Slave 0" description="Slave 0"/>
175 <option event_delta="0x30" name="Slave 1" description="Slave 1"/>
176 <option event_delta="0x40" name="Slave 2" description="Slave 2"/>
177 <option event_delta="0x50" name="Slave 3" description="Slave 3"/>
178 <option event_delta="0x60" name="Slave 4" description="Slave 4"/>
179 </option_set>
180 <event event="0x00" option_set="All" title="Mali L2 Cache 2" name="Read transactions" description="Read transactions"/>
181 <event event="0x01" option_set="All" title="Mali L2 Cache 2" name="Write transactions" description="Write transactions"/>
182 <event event="0x02" option_set="All" title="Mali L2 Cache 2" name="Words read" description="Words read"/>
183 <event event="0x03" option_set="All" title="Mali L2 Cache 2" name="Words written" description="Words written"/>
184 <event event="0x04" option_set="Slaves" title="Mali L2 Cache 2" name="Read hits" description="Read hits"/>
185 <event event="0x05" option_set="Slaves" title="Mali L2 Cache 2" name="Read misses" description="Read misses"/>
186 <event event="0x06" option_set="Slaves" title="Mali L2 Cache 2" name="Write invalidates" description="Write invalidates"/>
187 <event event="0x07" option_set="Slaves" title="Mali L2 Cache 2" name="Read invalidates" description="Read invalidates"/>
188 <event event="0x08" option_set="Slaves" title="Mali L2 Cache 2" name="Cacheable read transactions" description="Cacheable read transactions"/>
189 </category>
190 <counter_set name="ARM_Mali-4xx_Filmstrip_cnt" count="1"/>
191 <category name="Mali-4xx Filmstrip" counter_set="ARM_Mali-4xx_Filmstrip_cnt" per_cpu="no">
192 <option_set name="fs">
193 <option event_delta="0x3c" name="1:60" description="captures every 60th frame"/>
194 <option event_delta="0x1e" name="1:30" description="captures every 30th frame"/>
195 <option event_delta="0xa" name="1:10" description="captures every 10th frame"/>
196 </option_set>
197 <event event="0x0400" option_set="fs" title="ARM Mali-4xx" name="Filmstrip" description="Scaled framebuffer"/>
198 </category>
199 <category name="ARM_Mali-4xx_Voltage" per_cpu="no">
200 <event counter="ARM_Mali-4xx_Voltage" title="Mali GPU Voltage" name="Voltage" class="absolute" display="average" average_selection="yes" units="mV" description="GPU core voltage."/>
201 </category>
202 <category name="ARM_Mali-4xx_Frequency" per_cpu="no">
203 <event counter="ARM_Mali-4xx_Frequency" title="Mali GPU Frequency" name="Frequency" display="average" average_selection="yes" units="MHz" description="GPU core frequency."/>
204 </category>
205 <category name="Mali-4xx Activity" counter_set="ARM_Mali-4xx_Activity_cnt">
206 <event counter="ARM_Mali-4xx_fragment" title="GPU Fragment" name="Activity" class="activity" activity1="Activity" activity_color1="0x00006fcc" rendering_type="bar" average_selection="yes" average_cores="yes" percentage="yes" description="GPU Fragment Activity"/>
207 <event counter="ARM_Mali-4xx_vertex" title="GPU Vertex" name="Activity" class="activity" activity1="Activity" activity_color1="0x00eda000" rendering_type="bar" average_selection="yes" percentage="yes" description="GPU Vertex Activity"/>
208 </category>
209 <category name="Mali-4xx Software Counters" counter_set="ARM_Mali-4xx_SW_cnt" per_cpu="no">
210 <!-- EGL Counters -->
211 <event counter="ARM_Mali-4xx_SW_0" title="Mali EGL Software Counters" name="Blit Time" description="Time spent blitting the framebuffer from video memory to framebuffer."/>
212 <!-- glDrawElements Counters -->
213 <event counter="ARM_Mali-4xx_SW_1" title="glDrawElements Statistics" name="Calls to glDrawElements" description="Number of calls to glDrawElements."/>
214 <event counter="ARM_Mali-4xx_SW_2" title="glDrawElements Statistics" name="Indices to glDrawElements" description="Number of indices to glDrawElements."/>
215 <event counter="ARM_Mali-4xx_SW_3" title="glDrawElements Statistics" name="Transformed by glDrawElements" description="Number of vertices transformed by glDrawElements."/>
216 <!-- glDrawArrays Counters -->
217 <event counter="ARM_Mali-4xx_SW_4" title="glDrawArrays Statistics" name="Calls to glDrawArrays" description="Number of calls to glDrawArrays."/>
218 <event counter="ARM_Mali-4xx_SW_5" title="glDrawArrays Statistics" name="Transformed by glDrawArrays" description="Number of vertices transformed by glDrawArrays."/>
219 <!-- Draw Call Counters -->
220 <event counter="ARM_Mali-4xx_SW_6" title="Drawcall Statistics" name="Points" description="Number of calls to glDraw* with parameter GL_POINTS."/>
221 <event counter="ARM_Mali-4xx_SW_7" title="Drawcall Statistics" name="Lines" description="Number of calls to glDraw* with parameter GL_LINES."/>
222 <event counter="ARM_Mali-4xx_SW_8" title="Drawcall Statistics" name="Lineloop" description="Number of calls to glDraw* with parameter GL_LINE_LOOP."/>
223 <event counter="ARM_Mali-4xx_SW_9" title="Drawcall Statistics" name="Linestrip" description="Number of calls to glDraw* with parameter GL_LINE_STRIP."/>
224 <event counter="ARM_Mali-4xx_SW_10" title="Drawcall Statistics" name="Triangles" description="Number of calls to glDraw* with parameter GL_TRIANGLES."/>
225 <event counter="ARM_Mali-4xx_SW_11" title="Drawcall Statistics" name="Trianglestrip" description="Number of calls to glDraw* with parameter GL_TRIANGLE_STRIP."/>
226 <event counter="ARM_Mali-4xx_SW_12" title="Drawcall Statistics" name="Trianglefan" description="Number of calls to glDraw* with parameter GL_TRIANGLE_FAN."/>
227 <event counter="ARM_Mali-4xx_SW_13" title="Drawcall Statistics" name="Vertex Upload Time (us)" description="Time spent uploading vertex attributes and faceindex data not present in a VBO."/>
228 <event counter="ARM_Mali-4xx_SW_14" title="Drawcall Statistics" name="Uniform Bytes Copied (bytes)" description="Number of bytes copied to Mali memory as a result of uniforms update."/>
229 <!-- Buffer Profiling Counters -->
230 <event counter="ARM_Mali-4xx_SW_15" title="Buffer Profiling" name="Texture Upload Time (ms)" description="Time spent uploading textures."/>
231 <event counter="ARM_Mali-4xx_SW_16" title="Buffer Profiling" name="VBO Upload Time (ms)" description="Time spent uploading vertex buffer objects."/>
232 <event counter="ARM_Mali-4xx_SW_17" title="Buffer Profiling" name="FBO Flushes" description="Number of flushed on framebuffer attachment."/>
233 <!-- OpenGL ES 1.1 Emulation -->
234 <event counter="ARM_Mali-4xx_SW_18" title="Fixed-function Emulation" name="# Vertex Shaders Generated" description="Number of vertex shaders generated."/>
235 <event counter="ARM_Mali-4xx_SW_19" title="Fixed-function Emulation" name="# Fragment Shaders Generated" description="Number of fragment shaders generated."/>
236 <!-- Geometry Statistics -->
237 <event counter="ARM_Mali-4xx_SW_33" title="Geometry Statistics" name="Triangles" description="The total number of triangles passed to GLES per-frame."/>
238 <event counter="ARM_Mali-4xx_SW_34" title="Geometry Statistics" name="Independent Triangles" description="Number of triangles passed to GLES using the mode GL_TRIANGLES."/>
239 <event counter="ARM_Mali-4xx_SW_35" title="Geometry Statistics" name="Strip Triangles" description="Number of triangles passed to GLES using the mode GL_TRIANGLE_STRIP."/>
240 <event counter="ARM_Mali-4xx_SW_36" title="Geometry Statistics" name="Fan Triangles" description="Number of triangles passed to GLES using the mode GL_TRIANGLE_FAN."/>
241 <event counter="ARM_Mali-4xx_SW_37" title="Geometry Statistics" name="Lines" description="Number of lines passed to GLES per-frame."/>
242 <event counter="ARM_Mali-4xx_SW_38" title="Geometry Statistics" name="Independent Lines" description="Number of lines passed to GLES using the mode GL_LINES."/>
243 <event counter="ARM_Mali-4xx_SW_39" title="Geometry Statistics" name="Strip Lines" description="Number of lines passed to GLES using the mode GL_LINE_STRIP."/>
244 <event counter="ARM_Mali-4xx_SW_40" title="Geometry Statistics" name="Loop Lines" description="Number of lines passed to GLES using the mode GL_LINE_LOOP."/>
245 </category>
diff --git a/tools/gator/daemon/events-Mali-T6xx.xml b/tools/gator/daemon/events-Mali-T6xx.xml
new file mode 100644
index 00000000000..5e897970487
--- /dev/null
+++ b/tools/gator/daemon/events-Mali-T6xx.xml
@@ -0,0 +1,46 @@
1 <category name="Mali-T6xx Software Counters" per_cpu="no">
2 <event counter="ARM_Mali-T6xx_TOTAL_ALLOC_PAGES" title="Mali Total Alloc Pages" name="Total number of allocated pages" description="Mali total number of allocated pages."/>
3 </category>
4 <category name="Mali-T6xx PM Shader" per_cpu="no">
5 <event counter="ARM_Mali-T6xx_PM_SHADER_0" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 0" description="Mali PM Shader: PM Shader Core 0."/>
6 <event counter="ARM_Mali-T6xx_PM_SHADER_1" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 1" description="Mali PM Shader: PM Shader Core 1."/>
7 <event counter="ARM_Mali-T6xx_PM_SHADER_2" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 2" description="Mali PM Shader: PM Shader Core 2."/>
8 <event counter="ARM_Mali-T6xx_PM_SHADER_3" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 3" description="Mali PM Shader: PM Shader Core 3."/>
9 <event counter="ARM_Mali-T6xx_PM_SHADER_4" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 4" description="Mali PM Shader: PM Shader Core 4."/>
10 <event counter="ARM_Mali-T6xx_PM_SHADER_5" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 5" description="Mali PM Shader: PM Shader Core 5."/>
11 <event counter="ARM_Mali-T6xx_PM_SHADER_6" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 6" description="Mali PM Shader: PM Shader Core 6."/>
12 <event counter="ARM_Mali-T6xx_PM_SHADER_7" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 7" description="Mali PM Shader: PM Shader Core 7."/>
13 </category>
14 <category name="Mali-T6xx PM Tiler" per_cpu="no">
15 <event counter="ARM_Mali-T6xx_PM_TILER_0" display="average" average_selection="yes" percentage="yes" title="Mali PM Tiler" name="PM Tiler Core 0" description="Mali PM Tiler: PM Tiler Core 0."/>
16 </category>
17 <category name="Mali-T6xx PM L2" per_cpu="no">
18 <event counter="ARM_Mali-T6xx_PM_L2_0" display="average" average_selection="yes" percentage="yes" title="Mali PM L2" name="PM L2 Core 0" description="Mali PM L2: PM L2 Core 0."/>
19 <event counter="ARM_Mali-T6xx_PM_L2_1" display="average" average_selection="yes" percentage="yes" title="Mali PM L2" name="PM L2 Core 1" description="Mali PM L2: PM L2 Core 1."/>
20 </category>
21 <category name="Mali-T6xx MMU Address Space" per_cpu="no">
22 <event counter="ARM_Mali-T6xx_MMU_AS_0" display="average" average_selection="yes" percentage="yes" title="Mali MMU Address Space" name="MMU Address Space 0" description="Mali MMU Address Space 0 usage."/>
23 <event counter="ARM_Mali-T6xx_MMU_AS_1" display="average" average_selection="yes" percentage="yes" title="Mali MMU Address Space" name="MMU Address Space 1" description="Mali MMU Address Space 1 usage."/>
24 <event counter="ARM_Mali-T6xx_MMU_AS_2" display="average" average_selection="yes" percentage="yes" title="Mali MMU Address Space" name="MMU Address Space 2" description="Mali MMU Address Space 2 usage."/>
25 <event counter="ARM_Mali-T6xx_MMU_AS_3" display="average" average_selection="yes" percentage="yes" title="Mali MMU Address Space" name="MMU Address Space 3" description="Mali MMU Address Space 3 usage."/>
26 </category>
27 <category name="Mali-T6xx MMU Page Fault" per_cpu="no">
28 <event counter="ARM_Mali-T6xx_MMU_PAGE_FAULT_0" title="Mali MMU Page Fault Add. Space" name="Mali MMU Page Fault Add. Space 0" description="Reports the number of newly allocated pages after a MMU page fault in address space 0."/>
29 <event counter="ARM_Mali-T6xx_MMU_PAGE_FAULT_1" title="Mali MMU Page Fault Add. Space" name="Mali MMU Page Fault Add. Space 1" description="Reports the number of newly allocated pages after a MMU page fault in address space 1."/>
30 <event counter="ARM_Mali-T6xx_MMU_PAGE_FAULT_2" title="Mali MMU Page Fault Add. Space" name="Mali MMU Page Fault Add. Space 2" description="Reports the number of newly allocated pages after a MMU page fault in address space 2."/>
31 <event counter="ARM_Mali-T6xx_MMU_PAGE_FAULT_3" title="Mali MMU Page Fault Add. Space" name="Mali MMU Page Fault Add. Space 3" description="Reports the number of newly allocated pages after a MMU page fault in address space 3."/>
32 </category>
33 <counter_set name="ARM_Mali-T6xx_Filmstrip_cnt" count="1"/>
34 <category name="Mali-T6xx Filmstrip" counter_set="ARM_Mali-T6xx_Filmstrip_cnt" per_cpu="no">
35 <option_set name="fs">
36 <option event_delta="0x3c" name="1:60" description="captures every 60th frame"/>
37 <option event_delta="0x1e" name="1:30" description="captures every 30th frame"/>
38 <option event_delta="0xa" name="1:10" description="captures every 10th frame"/>
39 </option_set>
40 <event event="0x0400" option_set="fs" title="ARM Mali-T6xx" name="Filmstrip" description="Scaled framebuffer"/>
41 </category>
42 <category name="Mali-T6xx Activity" per_cpu="no">
43 <event counter="ARM_Mali-T6xx_fragment" title="GPU Fragment" name="Activity" class="activity" activity1="Activity" activity_color1="0x00006fcc" rendering_type="bar" average_selection="yes" percentage="yes" cores="1" description="GPU Job Slot 0 Activity"/>
44 <event counter="ARM_Mali-T6xx_vertex" title="GPU Vertex-Tiling-Compute" name="Activity" class="activity" activity1="Activity" activity_color1="0x00eda000" rendering_type="bar" average_selection="yes" percentage="yes" cores="1" description="GPU Job Slot 1 Activity"/>
45 <event counter="ARM_Mali-T6xx_opencl" title="GPU Vertex-Compute" name="Activity" class="activity" activity1="Activity" activity_color1="0x00ef022f" rendering_type="bar" average_selection="yes" percentage="yes" cores="1" description="GPU Job Slot 2 Activity"/>
46 </category>
diff --git a/tools/gator/daemon/events-Mali-T6xx_hw.xml b/tools/gator/daemon/events-Mali-T6xx_hw.xml
new file mode 100644
index 00000000000..df279626247
--- /dev/null
+++ b/tools/gator/daemon/events-Mali-T6xx_hw.xml
@@ -0,0 +1,91 @@
1 <category name="Mali-T6xx Job Manager" per_cpu="no">
2 <event counter="ARM_Mali-T6xx_GPU_ACTIVE" title="Mali Job Manager Cycles" name="GPU cycles" description="Number of cycles the GPU was active"/>
3 <event counter="ARM_Mali-T6xx_IRQ_ACTIVE" title="Mali Job Manager Cycles" name="IRQ cycles" description="Number of cycles the GPU had a pending interrupt"/>
4 <event counter="ARM_Mali-T6xx_JS0_ACTIVE" title="Mali Job Manager Cycles" name="JS0 cycles" description="Number of cycles JS0 (fragment) was active"/>
5 <event counter="ARM_Mali-T6xx_JS1_ACTIVE" title="Mali Job Manager Cycles" name="JS1 cycles" description="Number of cycles JS1 (vertex/tiler/compute) was active"/>
6 <event counter="ARM_Mali-T6xx_JS2_ACTIVE" title="Mali Job Manager Cycles" name="JS2 cycles" description="Number of cycles JS2 (vertex/compute) was active"/>
7 <event counter="ARM_Mali-T6xx_JS0_JOBS" title="Mali Job Manager Work" name="JS0 jobs" description="Number of Jobs (fragment) completed in JS0"/>
8 <event counter="ARM_Mali-T6xx_JS0_TASKS" title="Mali Job Manager Work" name="JS0 tasks" description="Number of Tasks completed in JS0"/>
9 <event counter="ARM_Mali-T6xx_JS1_JOBS" title="Mali Job Manager Work" name="JS1 jobs" description="Number of Jobs (vertex/tiler/compute) completed in JS1"/>
10 <event counter="ARM_Mali-T6xx_JS1_TASKS" title="Mali Job Manager Work" name="JS1 tasks" description="Number of Tasks completed in JS1"/>
11 <event counter="ARM_Mali-T6xx_JS2_TASKS" title="Mali Job Manager Work" name="JS2 tasks" description="Number of Tasks completed in JS2"/>
12 <event counter="ARM_Mali-T6xx_JS2_JOBS" title="Mali Job Manager Work" name="JS2 jobs" description="Number of Jobs (vertex/compute) completed in JS2"/>
13 </category>
14 <category name="Mali-T6xx Tiler" per_cpu="no">
15 <event counter="ARM_Mali-T6xx_POLYGONS" title="Mali Tiler Primitives" name="Polygons" description="Number of polygons processed"/>
16 <event counter="ARM_Mali-T6xx_QUADS" title="Mali Tiler Primitives" name="Quads" description="Number of quads processed"/>
17 <event counter="ARM_Mali-T6xx_TRIANGLES" title="Mali Tiler Primitives" name="Triangles" description="Number of triangles processed"/>
18 <event counter="ARM_Mali-T6xx_LINES" title="Mali Tiler Primitives" name="Lines" description="Number of lines processed"/>
19 <event counter="ARM_Mali-T6xx_POINTS" title="Mali Tiler Primitives" name="Points" description="Number of points processed"/>
20 <event counter="ARM_Mali-T6xx_FRONT_FACING" title="Mali Tiler Culling" name="Front facing prims" description="Number of front facing primitives"/>
21 <event counter="ARM_Mali-T6xx_BACK_FACING" title="Mali Tiler Culling" name="Back facing prims" description="Number of back facing primitives"/>
22 <event counter="ARM_Mali-T6xx_PRIM_VISIBLE" title="Mali Tiler Culling" name="Visible prims" description="Number of visible primitives"/>
23 <event counter="ARM_Mali-T6xx_PRIM_CULLED" title="Mali Tiler Culling" name="Culled prims" description="Number of culled primitives"/>
24 <event counter="ARM_Mali-T6xx_PRIM_CLIPPED" title="Mali Tiler Culling" name="Clipped prims" description="Number of clipped primitives"/>
25 <event counter="ARM_Mali-T6xx_LEVEL0" title="Mali Tiler Hierarchy" name="L0 prims" description="Number of primitives in hierarchy level 0"/>
26 <event counter="ARM_Mali-T6xx_LEVEL1" title="Mali Tiler Hierarchy" name="L1 prims" description="Number of primitives in hierarchy level 1"/>
27 <event counter="ARM_Mali-T6xx_LEVEL2" title="Mali Tiler Hierarchy" name="L2 prims" description="Number of primitives in hierarchy level 2"/>
28 <event counter="ARM_Mali-T6xx_LEVEL3" title="Mali Tiler Hierarchy" name="L3 prims" description="Number of primitives in hierarchy level 3"/>
29 <event counter="ARM_Mali-T6xx_LEVEL4" title="Mali Tiler Hierarchy" name="L4 prims" description="Number of primitives in hierarchy level 4"/>
30 <event counter="ARM_Mali-T6xx_LEVEL5" title="Mali Tiler Hierarchy" name="L5 prims" description="Number of primitives in hierarchy level 5"/>
31 <event counter="ARM_Mali-T6xx_LEVEL6" title="Mali Tiler Hierarchy" name="L6 prims" description="Number of primitives in hierarchy level 6"/>
32 <event counter="ARM_Mali-T6xx_LEVEL7" title="Mali Tiler Hierarchy" name="L7 prims" description="Number of primitives in hierarchy level 7"/>
33 <event counter="ARM_Mali-T6xx_COMMAND_1" title="Mali Tiler Commands" name="Prims in 1 command" description="Number of primitives producing 1 command"/>
34 <event counter="ARM_Mali-T6xx_COMMAND_2" title="Mali Tiler Commands" name="Prims in 2 command" description="Number of primitives producing 2 commands"/>
35 <event counter="ARM_Mali-T6xx_COMMAND_3" title="Mali Tiler Commands" name="Prims in 3 command" description="Number of primitives producing 3 commands"/>
36 <event counter="ARM_Mali-T6xx_COMMAND_4" title="Mali Tiler Commands" name="Prims in 4 command" description="Number of primitives producing 4 commands"/>
37 <event counter="ARM_Mali-T6xx_COMMAND_4_7" title="Mali Tiler Commands" name="Prims in 4-7 commands" description="Number of primitives producing 4-7 commands"/>
38 <event counter="ARM_Mali-T6xx_COMMAND_5_7" title="Mali Tiler Commands" name="Prims in 5-7 commands" description="Number of primitives producing 5-7 commands"/>
39 <event counter="ARM_Mali-T6xx_COMMAND_8_15" title="Mali Tiler Commands" name="Prims in 8-15 commands" description="Number of primitives producing 8-15 commands"/>
40 <event counter="ARM_Mali-T6xx_COMMAND_16_63" title="Mali Tiler Commands" name="Prims in 16-63 commands" description="Number of primitives producing 16-63 commands"/>
41 <event counter="ARM_Mali-T6xx_COMMAND_64" title="Mali Tiler Commands" name="Prims in &gt;= 64 commands" description="Number of primitives producing &gt;= 64 commands"/>
42 </category>
43 <category name="Mali-T6xx Shader Core" per_cpu="no">
44 <event counter="ARM_Mali-T6xx_TRIPIPE_ACTIVE" title="Mali Core Cycles" name="Tripipe cycles" description="Number of cycles the Tripipe was active"/>
45 <event counter="ARM_Mali-T6xx_FRAG_ACTIVE" title="Mali Core Cycles" name="Fragment cycles" description="Number of cycles fragment processing was active"/>
46 <event counter="ARM_Mali-T6xx_COMPUTE_ACTIVE" title="Mali Core Cycles" name="Compute cycles" description="Number of cycles vertex\compute processing was active"/>
47 <event counter="ARM_Mali-T6xx_FRAG_CYCLE_NO_TILE" title="Mali Core Cycles" name="Fragment cycles waiting for tile" description="Number of cycles spent waiting for a physical tile buffer"/>
48 <event counter="ARM_Mali-T6xx_FRAG_THREADS" title="Mali Core Threads" name="Fragment threads" description="Number of fragment threads started"/>
49 <event counter="ARM_Mali-T6xx_FRAG_DUMMY_THREADS" title="Mali Core Threads" name="Dummy fragment threads" description="Number of dummy fragment threads started"/>
50 <event counter="ARM_Mali-T6xx_FRAG_QUADS_LZS_TEST" title="Mali Core Threads" name="Frag threads doing late ZS" description="Number of threads doing late ZS test"/>
51 <event counter="ARM_Mali-T6xx_FRAG_QUADS_LZS_KILLED" title="Mali Core Threads" name="Frag threads killed late ZS" description="Number of threads killed by late ZS test"/>
52 <event counter="ARM_Mali-T6xx_FRAG_THREADS_LZS_TEST" title="Mali Core Threads" name="Frag threads doing late ZS" description="Number of threads doing late ZS test"/>
53 <event counter="ARM_Mali-T6xx_FRAG_THREADS_LZS_KILLED" title="Mali Core Threads" name="Frag threads killed late ZS" description="Number of threads killed by late ZS test"/>
54 <event counter="ARM_Mali-T6xx_COMPUTE_TASKS" title="Mali Compute Threads" name="Compute tasks" description="Number of compute tasks"/>
55 <event counter="ARM_Mali-T6xx_COMPUTE_THREADS" title="Mali Compute Threads" name="Compute threads started" description="Number of compute threads started"/>
56 <event counter="ARM_Mali-T6xx_COMPUTE_CYCLES_DESC" title="Mali Compute Threads" name="Compute cycles awaiting descriptors" description="Number of compute cycles spent waiting for descriptors"/>
57 <event counter="ARM_Mali-T6xx_FRAG_PRIMATIVES" title="Mali Fragment Primitives" name="Primitives loaded" description="Number of primitives loaded from tiler"/>
58 <event counter="ARM_Mali-T6xx_FRAG_PRIMATIVES_DROPPED" title="Mali Fragment Primitives" name="Primitives dropped" description="Number of primitives dropped because out of tile"/>
59 <event counter="ARM_Mali-T6xx_FRAG_PRIMITIVES" title="Mali Fragment Primitives" name="Primitives loaded" description="Number of primitives loaded from tiler"/>
60 <event counter="ARM_Mali-T6xx_FRAG_PRIMITIVES_DROPPED" title="Mali Fragment Primitives" name="Primitives dropped" description="Number of primitives dropped because out of tile"/>
61 <event counter="ARM_Mali-T6xx_FRAG_QUADS_RAST" title="Mali Fragment Quads" name="Quads rasterized" description="Number of quads rasterized"/>
62 <event counter="ARM_Mali-T6xx_FRAG_QUADS_EZS_TEST" title="Mali Fragment Quads" name="Quads doing early ZS" description="Number of quads doing early ZS test"/>
63 <event counter="ARM_Mali-T6xx_FRAG_QUADS_EZS_KILLED" title="Mali Fragment Quads" name="Quads killed early Z" description="Number of quads killed by early ZS test"/>
64 <event counter="ARM_Mali-T6xx_FRAG_NUM_TILES" title="Mali Fragment Tasks" name="Tiles rendered" description="Number of tiles rendered"/>
65 <event counter="ARM_Mali-T6xx_FRAG_TRANS_ELIM" title="Mali Fragment Tasks" name="Tile writes killed by TE" description="Number of tile writes skipped by transaction elimination"/>
66 <event counter="ARM_Mali-T6xx_ARITH_WORDS" title="Mali Arithmetic Pipe" name="A instructions" description="Number of instructions completed by the the A-pipe (normalized per pipeline)"/>
67 <event counter="ARM_Mali-T6xx_LS_WORDS" title="Mali Load/Store Pipe" name="LS instructions" description="Number of instructions completed by the LS-pipe"/>
68 <event counter="ARM_Mali-T6xx_LS_ISSUES" title="Mali Load/Store Pipe" name="LS instruction issues" description="Number of instructions issued to the LS-pipe, including restarts"/>
69 <event counter="ARM_Mali-T6xx_TEX_WORDS" title="Mali Texture Pipe" name="T instructions" description="Number of instructions completed by the T-pipe"/>
70 <event counter="ARM_Mali-T6xx_TEX_THREADS" title="Mali Texture Pipe" name="T instruction issues" description="Number of instructions issused to the T-pipe, including restarts"/>
71 <event counter="ARM_Mali-T6xx_TEX_RECIRC_FMISS" title="Mali Texture Pipe" name="Cache misses" description="Number of instructions in the T-pipe, recirculated due to cache miss"/>
72 <event counter="ARM_Mali-T6xx_LSC_READ_HITS" title="Mali Load/Store Cache" name="Read hits" description="Number of read hits in the Load/Store cache"/>
73 <event counter="ARM_Mali-T6xx_LSC_READ_MISSES" title="Mali Load/Store Cache" name="Read misses" description="Number of read misses in the Load/Store cache"/>
74 <event counter="ARM_Mali-T6xx_LSC_WRITE_HITS" title="Mali Load/Store Cache" name="Write hits" description="Number of write hits in the Load/Store cache"/>
75 <event counter="ARM_Mali-T6xx_LSC_WRITE_MISSES" title="Mali Load/Store Cache" name="Write misses" description="Number of write misses in the Load/Store cache"/>
76 <event counter="ARM_Mali-T6xx_LSC_ATOMIC_HITS" title="Mali Load/Store Cache" name="Atomic hits" description="Number of atomic hits in the Load/Store cache"/>
77 <event counter="ARM_Mali-T6xx_LSC_ATOMIC_MISSES" title="Mali Load/Store Cache" name="Atomic misses" description="Number of atomic misses in the Load/Store cache"/>
78 <event counter="ARM_Mali-T6xx_LSC_LINE_FETCHES" title="Mali Load/Store Cache" name="Line fetches" description="Number of line fetches in the Load/Store cache"/>
79 <event counter="ARM_Mali-T6xx_LSC_DIRTY_LINE" title="Mali Load/Store Cache" name="Dirty line evictions" description="Number of dirty line evictions in the Load/Store cache"/>
80 <event counter="ARM_Mali-T6xx_LSC_SNOOPS" title="Mali Load/Store Cache" name="Snoops in to LSC" description="Number of coherent memory snoops in to the Load/Store cache"/>
81 </category>
82 <category name="Mali-T6xx L2 and MMU" per_cpu="no">
83 <event counter="ARM_Mali-T6xx_L2_WRITE_BEATS" title="Mali L2 Cache" name="External write beats" description="Number of external bus write beats"/>
84 <event counter="ARM_Mali-T6xx_L2_READ_BEATS" title="Mali L2 Cache" name="External read beats" description="Number of external bus read beats"/>
85 <event counter="ARM_Mali-T6xx_L2_READ_SNOOP" title="Mali L2 Cache" name="Read snoops" description="Number of read transaction snoops"/>
86 <event counter="ARM_Mali-T6xx_L2_READ_HIT" title="Mali L2 Cache" name="L2 read hits" description="Number of reads hitting in the L2 cache"/>
87 <event counter="ARM_Mali-T6xx_L2_WRITE_SNOOP" title="Mali L2 Cache" name="Write snoops" description="Number of write transaction snoops"/>
88 <event counter="ARM_Mali-T6xx_L2_WRITE_HIT" title="Mali L2 Cache" name="L2 write hits" description="Number of writes hitting in the L2 cache"/>
89 <event counter="ARM_Mali-T6xx_L2_EXT_AR_STALL" title="Mali L2 Cache" name="External bus stalls (AR)" description="Number of cycles a valid read address (AR) is stalled by the external interconnect"/>
90 <event counter="ARM_Mali-T6xx_L2_EXT_W_STALL" title="Mali L2 Cache" name="External bus stalls (W)" description="Number of cycles a valid write data (W channel) is stalled by the external interconnect"/>
91 </category>
diff --git a/tools/gator/daemon/events-Mali-V500.xml b/tools/gator/daemon/events-Mali-V500.xml
new file mode 100644
index 00000000000..d2751e7239b
--- /dev/null
+++ b/tools/gator/daemon/events-Mali-V500.xml
@@ -0,0 +1,29 @@
1 <category name="Mali-V500">
2 <event counter="ARM_Mali-V500_cnt0" title="Mali Video Engine" name="Samples" class="absolute" description="The number of times we have taken a sample"/>
3 <event counter="ARM_Mali-V500_cnt1" title="Mali Video Engine" name="Queued input-buffers" class="absolute" description="The number of input-buffers that has been queued for consumption by the MVE"/>
4 <event counter="ARM_Mali-V500_cnt2" title="Mali Video Engine" name="Consumed input-buffers" class="absolute" description="The number of input-buffers that has been consumed by the MVE and returned to the application"/>
5 <event counter="ARM_Mali-V500_cnt3" title="Mali Video Engine" name="Queued output-buffers" class="absolute" description="The number of output-buffers that has been queued for usage by the MVE"/>
6 <event counter="ARM_Mali-V500_cnt4" title="Mali Video Engine" name="Consumed output-buffers" class="absolute" description="The number of output-buffers that has been consumed by the MVE and returned to the application"/>
7 <event counter="ARM_Mali-V500_cnt5" title="Mali Video Engine" name="Created Sessions" class="absolute" description="The number of created sessions throughout the lifetime of the process"/>
8 <event counter="ARM_Mali-V500_cnt6" title="Mali Video Engine" name="Active Sessions" description="The number of currently existing sessions"/>
9 <event counter="ARM_Mali-V500_cnt7" title="Mali Video Engine" name="Processed Frames" class="absolute" description="The number of processed frames. A processed frame is one where the encode or decode is complete for that particular frame. Frames can be processed out of order so this is not the same as the number of output-buffers returned"/>
10 <event counter="ARM_Mali-V500_cnt8" title="Mali Video Engine" name="Input Flushes Requested" class="absolute" description="The number of requested flushes of the input queue"/>
11 <event counter="ARM_Mali-V500_cnt9" title="Mali Video Engine" name="Input Flushes Complete" class="absolute" description="The number of completed flushes of the input queue"/>
12 <event counter="ARM_Mali-V500_cnt10" title="Mali Video Engine" name="Output Flushes Requested" class="absolute" description="The number of requested flushes of the output queue"/>
13 <event counter="ARM_Mali-V500_cnt11" title="Mali Video Engine" name="Output Flushes Complete" class="absolute" description="The number of completed flushes of the output queue"/>
14 <event counter="ARM_Mali-V500_cnt12" title="Mali Video Engine" name="Queued Output Buffers (current)" description="The number of output-buffers that are currently queued for usage by the MVE"/>
15 <event counter="ARM_Mali-V500_cnt13" title="Mali Video Engine" name="Queued Input Buffers (current)" description="The number of input-buffers that are currently queued for consumption by the MVE"/>
16 <event counter="ARM_Mali-V500_cnt14" title="Mali Video Engine" name="Output Queue Flushes" description="The number of pending flushes for the MVE output-queue"/>
17 <event counter="ARM_Mali-V500_cnt15" title="Mali Video Engine" name="Input Queue Flushes" description="The number of pending flushes for the MVE input-queue"/>
18 <event counter="ARM_Mali-V500_cnt16" title="Mali Video Engine" name="Errors encountered" class="absolute" description="The number of errors encountered"/>
19 <event counter="ARM_Mali-V500_cnt17" title="Mali Video Engine" name="Bits consumed" class="absolute" description="The number of bits consumed during decode"/>
20 <event counter="ARM_Mali-V500_cnt18" title="Mali Video Engine" name="AFBC bandwidth" class="absolute" description="The amount of AFBC-encoded bytes read or written"/>
21 <event counter="ARM_Mali-V500_cnt19" title="Mali Video Engine" name="Bandwidth (read)" class="absolute" description="The amount of bytes read over the AXI bus"/>
22 <event counter="ARM_Mali-V500_cnt20" title="Mali Video Engine" name="Bandwidth (write)" class="absolute" description="The amount of bytes written over the AXI bus"/>
23 <event counter="ARM_Mali-V500_evn0" title="Mali Video Engine" name="Session created" description="Generated when a session has been created"/>
24 <event counter="ARM_Mali-V500_evn1" title="Mali Video Engine" name="Session destroyed" description="Generated when a session has been destroyed"/>
25 <event counter="ARM_Mali-V500_evn2" title="Mali Video Engine" name="Frame Processed" description="Generated when the MVE has finished processing a frame"/>
26 <event counter="ARM_Mali-V500_evn3" title="Mali Video Engine" name="Output buffer received" description="Generated when an an output buffer is returned to us from the MVE"/>
27 <event counter="ARM_Mali-V500_evn4" title="Mali Video Engine" name="Input buffer received" description="Generated when we an input buffer is returned to us from the MVE"/>
28 <!--event counter="ARM_Mali-V500_act" title="VPU" name="Activity" class="activity" activity1="Parsed" activity_color1="0x000000ff" activity2="Piped" activity_color2="0x0000ff00" rendering_type="bar" average_selection="yes" average_cores="yes" percentage="yes" cores="8" description="Mali-V500 Activity"/-->
29 </category>
diff --git a/tools/gator/daemon/events-Perf-Hardware.xml b/tools/gator/daemon/events-Perf-Hardware.xml
new file mode 100644
index 00000000000..423696f8242
--- /dev/null
+++ b/tools/gator/daemon/events-Perf-Hardware.xml
@@ -0,0 +1,12 @@
1 <counter_set name="Perf_Hardware_cnt" count="6"/>
2 <category name="Perf Hardware" counter_set="Perf_Hardware_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="Perf_Hardware_ccnt" event="0" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
4 <event event="1" title="Instruction" name="Executed" description="Instruction executed"/>
5 <event event="2" title="Cache" name="References" description="Cache References"/>
6 <event event="3" title="Cache" name="Misses" description="Cache Misses"/>
7 <event event="4" title="Branch" name="Instructions" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
8 <event event="5" title="Branch" name="Misses" description="Branch mispredicted or not predicted"/>
9 <event event="6" title="Bus" name="Cycles" description="Bus Cycles"/>
10 <event event="7" title="Instruction" name="Stalled Frontend" description="Stalled Frontend Cycles"/>
11 <event event="8" title="Instruction" name="Stalled Backend" description="Stalled Backend Cycles"/>
12 </category>
diff --git a/tools/gator/daemon/events-Scorpion.xml b/tools/gator/daemon/events-Scorpion.xml
new file mode 100644
index 00000000000..fa716fdc484
--- /dev/null
+++ b/tools/gator/daemon/events-Scorpion.xml
@@ -0,0 +1,107 @@
1 <counter_set name="Scorpion_cnt" count="4"/>
2 <category name="Scorpion" counter_set="Scorpion_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="Scorpion_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
7 <event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/>
8 <event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
9 <event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
10 <event event="0x06" title="Instruction" name="Memory read" description="Memory-reading instruction architecturally executed"/>
11 <event event="0x07" title="Instruction" name="Memory write" description="Memory-writing instruction architecturally executed"/>
12 <event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/>
13 <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
14 <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
15 <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
16 <event event="0x0c" title="Program Counter" name="SW change" description="Software change of PC, except by an exception, architecturally executed"/>
17 <event event="0x0d" title="Branch" name="Immediate" description="Immediate branch architecturally executed"/>
18 <event event="0x0e" title="Branch" name="Procedure Return" description="Procedure return architecturally executed (not by exceptions)"/>
19 <event event="0x0f" title="Memory" name="Unaligned access" description="Unaligned access architecturally executed"/>
20 <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
21 <event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
22 <event event="0x4c" title="Scorpion" name="ICACHE_EXPL_INV" description="I-cache explicit invalidates"/>
23 <event event="0x4d" title="Scorpion" name="ICACHE_MISS" description="I-cache misses"/>
24 <event event="0x4e" title="Scorpion" name="ICACHE_ACCESS" description="I-cache accesses"/>
25 <event event="0x4f" title="Scorpion" name="ICACHE_CACHEREQ_L2" description="I-cache cacheable requests to L2"/>
26 <event event="0x50" title="Scorpion" name="ICACHE_NOCACHE_L2" description="I-cache non-cacheable requests to L2"/>
27 <event event="0x51" title="Scorpion" name="HIQUP_NOPED" description="Conditional instructions HIQUPs NOPed"/>
28 <event event="0x52" title="Scorpion" name="DATA_ABORT" description="Interrupts and Exceptions Data Abort"/>
29 <event event="0x53" title="Scorpion" name="IRQ" description="Interrupts and Exceptions IRQ"/>
30 <event event="0x54" title="Scorpion" name="FIQ" description="Interrupts and Exceptions FIQ"/>
31 <event event="0x55" title="Scorpion" name="ALL_EXCPT" description="Interrupts and Exceptions All interrupts"/>
32 <event event="0x56" title="Scorpion" name="UNDEF" description="Interrupts and Exceptions Undefined"/>
33 <event event="0x57" title="Scorpion" name="SVC" description="Interrupts and Exceptions SVC"/>
34 <event event="0x58" title="Scorpion" name="SMC" description="Interrupts and Exceptions SMC"/>
35 <event event="0x59" title="Scorpion" name="PREFETCH_ABORT" description="Interrupts and Exceptions Prefetch Abort"/>
36 <event event="0x5a" title="Scorpion" name="INDEX_CHECK" description="Interrupts and Exceptions Index Check"/>
37 <event event="0x5b" title="Scorpion" name="NULL_CHECK" description="Interrupts and Exceptions Null Check"/>
38 <event event="0x5c" title="Scorpion" name="EXPL_ICIALLU" description="I-cache and BTAC Invalidates Explicit ICIALLU"/>
39 <event event="0x5d" title="Scorpion" name="IMPL_ICIALLU" description="I-cache and BTAC Invalidates Implicit ICIALLU"/>
40 <event event="0x5e" title="Scorpion" name="NONICIALLU_BTAC_INV" description="I-cache and BTAC Invalidates Non-ICIALLU BTAC Invalidate"/>
41 <event event="0x5f" title="Scorpion" name="ICIMVAU_IMPL_ICIALLU" description="I-cache and BTAC Invalidates ICIMVAU-implied ICIALLU"/>
42 <event event="0x60" title="Scorpion" name="SPIPE_ONLY_CYCLES" description="Issue S-pipe only issue cycles"/>
43 <event event="0x61" title="Scorpion" name="XPIPE_ONLY_CYCLES" description="Issue X-pipe only issue cycles"/>
44 <event event="0x62" title="Scorpion" name="DUAL_CYCLES" description="Issue dual issue cycles"/>
45 <event event="0x63" title="Scorpion" name="DISPATCH_ANY_CYCLES" description="Dispatch any dispatch cycles"/>
46 <event event="0x64" title="Scorpion" name="FIFO_FULLBLK_CMT" description="Commits Trace FIFO full Blk CMT"/>
47 <event event="0x65" title="Scorpion" name="FAIL_COND_INST" description="Conditional instructions failing conditional instrs (excluding branches)"/>
48 <event event="0x66" title="Scorpion" name="PASS_COND_INST" description="Conditional instructions passing conditional instrs (excluding branches)"/>
49 <event event="0x67" title="Scorpion" name="ALLOW_VU_CLK" description="Unit Clock Gating Allow VU Clks"/>
50 <event event="0x68" title="Scorpion" name="VU_IDLE" description="Unit Clock Gating VU Idle"/>
51 <event event="0x69" title="Scorpion" name="ALLOW_L2_CLK" description="Unit Clock Gating Allow L2 Clks"/>
52 <event event="0x6a" title="Scorpion" name="L2_IDLE" description="Unit Clock Gating L2 Idle"/>
53 <event event="0x6b" title="Scorpion" name="DTLB_IMPL_INV_SCTLR_DACR" description="DTLB implicit invalidates writes to SCTLR and DACR"/>
54 <event event="0x6c" title="Scorpion" name="DTLB_EXPL_INV" description="DTLB explicit invalidates"/>
55 <event event="0x6d" title="Scorpion" name="DTLB_MISS" description="DTLB misses"/>
56 <event event="0x6e" title="Scorpion" name="DTLB_ACCESS" description="DTLB accesses"/>
57 <event event="0x6f" title="Scorpion" name="ITLB_MISS" description="ITLB misses"/>
58 <event event="0x70" title="Scorpion" name="ITLB_IMPL_INV" description="ITLB implicit ITLB invalidates"/>
59 <event event="0x71" title="Scorpion" name="ITLB_EXPL_INV" description="ITLB explicit ITLB invalidates"/>
60 <event event="0x72" title="Scorpion" name="UTLB_D_MISS" description="UTLB d-side misses"/>
61 <event event="0x73" title="Scorpion" name="UTLB_D_ACCESS" description="UTLB d-side accesses"/>
62 <event event="0x74" title="Scorpion" name="UTLB_I_MISS" description="UTLB i-side misses"/>
63 <event event="0x75" title="Scorpion" name="UTLB_I_ACCESS" description="UTLB i-side accesses"/>
64 <event event="0x76" title="Scorpion" name="UTLB_INV_ASID" description="UTLB invalidate by ASID"/>
65 <event event="0x77" title="Scorpion" name="UTLB_INV_MVA" description="UTLB invalidate by MVA"/>
66 <event event="0x78" title="Scorpion" name="UTLB_INV_ALL" description="UTLB invalidate all"/>
67 <event event="0x79" title="Scorpion" name="S2_HOLD_RDQ_UNAVAIL" description="S2 hold RDQ unavail"/>
68 <event event="0x7a" title="Scorpion" name="S2_HOLD" description="S2 hold"/>
69 <event event="0x7b" title="Scorpion" name="S2_HOLD_DEV_OP" description="S2 hold device op"/>
70 <event event="0x7c" title="Scorpion" name="S2_HOLD_ORDER" description="S2 hold strongly ordered op"/>
71 <event event="0x7d" title="Scorpion" name="S2_HOLD_BARRIER" description="S2 hold barrier"/>
72 <event event="0x7e" title="Scorpion" name="VIU_DUAL_CYCLE" description="Scorpion VIU dual cycle"/>
73 <event event="0x7f" title="Scorpion" name="VIU_SINGLE_CYCLE" description="Scorpion VIU single cycle"/>
74 <event event="0x80" title="Scorpion" name="VX_PIPE_WAR_STALL_CYCLES" description="Scorpion VX pipe WAR cycles"/>
75 <event event="0x81" title="Scorpion" name="VX_PIPE_WAW_STALL_CYCLES" description="Scorpion VX pipe WAW cycles"/>
76 <event event="0x82" title="Scorpion" name="VX_PIPE_RAW_STALL_CYCLES" description="Scorpion VX pipe RAW cycles"/>
77 <event event="0x83" title="Scorpion" name="VX_PIPE_LOAD_USE_STALL" description="Scorpion VX pipe load use stall"/>
78 <event event="0x84" title="Scorpion" name="VS_PIPE_WAR_STALL_CYCLES" description="Scorpion VS pipe WAR stall cycles"/>
79 <event event="0x85" title="Scorpion" name="VS_PIPE_WAW_STALL_CYCLES" description="Scorpion VS pipe WAW stall cycles"/>
80 <event event="0x86" title="Scorpion" name="VS_PIPE_RAW_STALL_CYCLES" description="Scorpion VS pipe RAW stall cycles"/>
81 <event event="0x87" title="Scorpion" name="EXCEPTIONS_INV_OPERATION" description="Scorpion invalid operation exceptions"/>
82 <event event="0x88" title="Scorpion" name="EXCEPTIONS_DIV_BY_ZERO" description="Scorpion divide by zero exceptions"/>
83 <event event="0x89" title="Scorpion" name="COND_INST_FAIL_VX_PIPE" description="Scorpion conditional instruction fail VX pipe"/>
84 <event event="0x8a" title="Scorpion" name="COND_INST_FAIL_VS_PIPE" description="Scorpion conditional instruction fail VS pipe"/>
85 <event event="0x8b" title="Scorpion" name="EXCEPTIONS_OVERFLOW" description="Scorpion overflow exceptions"/>
86 <event event="0x8c" title="Scorpion" name="EXCEPTIONS_UNDERFLOW" description="Scorpion underflow exceptions"/>
87 <event event="0x8d" title="Scorpion" name="EXCEPTIONS_DENORM" description="Scorpion denorm exceptions"/>
88 <event event="0x8e" title="Scorpion" name="BANK_AB_HIT" description="L2 hit rates bank A/B hits"/>
89 <event event="0x8f" title="Scorpion" name="BANK_AB_ACCESS" description="L2 hit rates bank A/B accesses"/>
90 <event event="0x90" title="Scorpion" name="BANK_CD_HIT" description="L2 hit rates bank C/D hits"/>
91 <event event="0x91" title="Scorpion" name="BANK_CD_ACCESS" description="L2 hit rates bank C/D accesses"/>
92 <event event="0x92" title="Scorpion" name="BANK_AB_DSIDE_HIT" description="L2 hit rates bank A/B d-side hits"/>
93 <event event="0x93" title="Scorpion" name="BANK_AB_DSIDE_ACCESS" description="L2 hit rates bank A/B d-side accesses"/>
94 <event event="0x94" title="Scorpion" name="BANK_CD_DSIDE_HIT" description="L2 hit rates bank C/D d-side hits"/>
95 <event event="0x95" title="Scorpion" name="BANK_CD_DSIDE_ACCESS" description="L2 hit rates bank C/D d-side accesses"/>
96 <event event="0x96" title="Scorpion" name="BANK_AB_ISIDE_HIT" description="L2 hit rates bank A/B i-side hits"/>
97 <event event="0x97" title="Scorpion" name="BANK_AB_ISIDE_ACCESS" description="L2 hit rates bank A/B i-side accesses"/>
98 <event event="0x98" title="Scorpion" name="BANK_CD_ISIDE_HIT" description="L2 hit rates bank C/D i-side hits"/>
99 <event event="0x99" title="Scorpion" name="BANK_CD_ISIDE_ACCESS" description="L2 hit rates bank C/D i-side accesses"/>
100 <event event="0x9a" title="Scorpion" name="ISIDE_RD_WAIT" description="fills and castouts cycles that i-side RD requests wait on data from bus"/>
101 <event event="0x9b" title="Scorpion" name="DSIDE_RD_WAIT" description="fills and castouts cycles that d-side RD requests wait on data from bus"/>
102 <event event="0x9c" title="Scorpion" name="BANK_BYPASS_WRITE" description="fills and castouts bank bypass writes"/>
103 <event event="0x9d" title="Scorpion" name="BANK_AB_NON_CASTOUT" description="fills and castouts bank A/B non-castout writes to bus"/>
104 <event event="0x9e" title="Scorpion" name="BANK_AB_L2_CASTOUT" description="fills and castouts bank A/B L2 castouts (granules)"/>
105 <event event="0x9f" title="Scorpion" name="BANK_CD_NON_CASTOUT" description="fills and castouts bank C/D non-castout writes to bus"/>
106 <event event="0xa0" title="Scorpion" name="BANK_CD_L2_CASTOUT" description="fills and castouts bank C/D L2 castouts (granules)"/>
107 </category>
diff --git a/tools/gator/daemon/events-ScorpionMP.xml b/tools/gator/daemon/events-ScorpionMP.xml
new file mode 100644
index 00000000000..c648ccefb28
--- /dev/null
+++ b/tools/gator/daemon/events-ScorpionMP.xml
@@ -0,0 +1,90 @@
1 <counter_set name="ScorpionMP_cnt" count="4"/>
2 <category name="ScorpionMP" counter_set="ScorpionMP_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="ScorpionMP_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
7 <event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/>
8 <event event="0x04" title="Cache" name="Data access" description="Memory Read or Write operation that causes a cache access to at least the level of data or unified cache closest to the processor"/>
9 <event event="0x05" title="Cache" name="Data TLB refill" description="Memory Read or Write operation that causes a TLB refill of at least the level of TLB closest to the processor"/>
10 <event event="0x06" title="Instruction" name="Memory read" description="Memory-reading instruction architecturally executed"/>
11 <event event="0x07" title="Instruction" name="Memory write" description="Memory-writing instruction architecturally executed"/>
12 <event event="0x08" title="Instruction" name="Executed" description="Instruction architecturally executed"/>
13 <event event="0x09" title="Exception" name="Taken" description="Exceptions taken"/>
14 <event event="0x0a" title="Exception" name="Return" description="Exception return architecturally executed"/>
15 <event event="0x0b" title="Instruction" name="CONTEXTIDR" description="Instruction that writes to the CONTEXTIDR architecturally executed"/>
16 <event event="0x0c" title="Program Counter" name="SW change" description="Software change of PC, except by an exception, architecturally executed"/>
17 <event event="0x0d" title="Branch" name="Immediate" description="Immediate branch architecturally executed"/>
18 <event event="0x0e" title="Branch" name="Procedure Return" description="Procedure return architecturally executed (not by exceptions)"/>
19 <event event="0x0f" title="Memory" name="Unaligned access" description="Unaligned access architecturally executed"/>
20 <event event="0x10" title="Branch" name="Mispredicted" description="Branch mispredicted or not predicted"/>
21 <event event="0x12" title="Branch" name="Potential prediction" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
22 <event event="0x4c" title="Scorpion" name="ICACHE_EXPL_INV" description="I-cache explicit invalidates"/>
23 <event event="0x4d" title="Scorpion" name="ICACHE_MISS" description="I-cache misses"/>
24 <event event="0x4e" title="Scorpion" name="ICACHE_ACCESS" description="I-cache accesses"/>
25 <event event="0x4f" title="Scorpion" name="ICACHE_CACHEREQ_L2" description="I-cache cacheable requests to L2"/>
26 <event event="0x50" title="Scorpion" name="ICACHE_NOCACHE_L2" description="I-cache non-cacheable requests to L2"/>
27 <event event="0x51" title="Scorpion" name="HIQUP_NOPED" description="Conditional instructions HIQUPs NOPed"/>
28 <event event="0x52" title="Scorpion" name="DATA_ABORT" description="Interrupts and Exceptions Data Abort"/>
29 <event event="0x53" title="Scorpion" name="IRQ" description="Interrupts and Exceptions IRQ"/>
30 <event event="0x54" title="Scorpion" name="FIQ" description="Interrupts and Exceptions FIQ"/>
31 <event event="0x55" title="Scorpion" name="ALL_EXCPT" description="Interrupts and Exceptions All interrupts"/>
32 <event event="0x56" title="Scorpion" name="UNDEF" description="Interrupts and Exceptions Undefined"/>
33 <event event="0x57" title="Scorpion" name="SVC" description="Interrupts and Exceptions SVC"/>
34 <event event="0x58" title="Scorpion" name="SMC" description="Interrupts and Exceptions SMC"/>
35 <event event="0x59" title="Scorpion" name="PREFETCH_ABORT" description="Interrupts and Exceptions Prefetch Abort"/>
36 <event event="0x5a" title="Scorpion" name="INDEX_CHECK" description="Interrupts and Exceptions Index Check"/>
37 <event event="0x5b" title="Scorpion" name="NULL_CHECK" description="Interrupts and Exceptions Null Check"/>
38 <event event="0x5c" title="Scorpion" name="EXPL_ICIALLU" description="I-cache and BTAC Invalidates Explicit ICIALLU"/>
39 <event event="0x5d" title="Scorpion" name="IMPL_ICIALLU" description="I-cache and BTAC Invalidates Implicit ICIALLU"/>
40 <event event="0x5e" title="Scorpion" name="NONICIALLU_BTAC_INV" description="I-cache and BTAC Invalidates Non-ICIALLU BTAC Invalidate"/>
41 <event event="0x5f" title="Scorpion" name="ICIMVAU_IMPL_ICIALLU" description="I-cache and BTAC Invalidates ICIMVAU-implied ICIALLU"/>
42 <event event="0x60" title="Scorpion" name="SPIPE_ONLY_CYCLES" description="Issue S-pipe only issue cycles"/>
43 <event event="0x61" title="Scorpion" name="XPIPE_ONLY_CYCLES" description="Issue X-pipe only issue cycles"/>
44 <event event="0x62" title="Scorpion" name="DUAL_CYCLES" description="Issue dual issue cycles"/>
45 <event event="0x63" title="Scorpion" name="DISPATCH_ANY_CYCLES" description="Dispatch any dispatch cycles"/>
46 <event event="0x64" title="Scorpion" name="FIFO_FULLBLK_CMT" description="Commits Trace FIFO full Blk CMT"/>
47 <event event="0x65" title="Scorpion" name="FAIL_COND_INST" description="Conditional instructions failing conditional instrs (excluding branches)"/>
48 <event event="0x66" title="Scorpion" name="PASS_COND_INST" description="Conditional instructions passing conditional instrs (excluding branches)"/>
49 <event event="0x67" title="Scorpion" name="ALLOW_VU_CLK" description="Unit Clock Gating Allow VU Clks"/>
50 <event event="0x68" title="Scorpion" name="VU_IDLE" description="Unit Clock Gating VU Idle"/>
51 <event event="0x69" title="Scorpion" name="ALLOW_L2_CLK" description="Unit Clock Gating Allow L2 Clks"/>
52 <event event="0x6a" title="Scorpion" name="L2_IDLE" description="Unit Clock Gating L2 Idle"/>
53 <event event="0x6b" title="Scorpion" name="DTLB_IMPL_INV_SCTLR_DACR" description="DTLB implicit invalidates writes to SCTLR and DACR"/>
54 <event event="0x6c" title="Scorpion" name="DTLB_EXPL_INV" description="DTLB explicit invalidates"/>
55 <event event="0x6d" title="Scorpion" name="DTLB_MISS" description="DTLB misses"/>
56 <event event="0x6e" title="Scorpion" name="DTLB_ACCESS" description="DTLB accesses"/>
57 <event event="0x6f" title="Scorpion" name="ITLB_MISS" description="ITLB misses"/>
58 <event event="0x70" title="Scorpion" name="ITLB_IMPL_INV" description="ITLB implicit ITLB invalidates"/>
59 <event event="0x71" title="Scorpion" name="ITLB_EXPL_INV" description="ITLB explicit ITLB invalidates"/>
60 <event event="0x72" title="Scorpion" name="UTLB_D_MISS" description="UTLB d-side misses"/>
61 <event event="0x73" title="Scorpion" name="UTLB_D_ACCESS" description="UTLB d-side accesses"/>
62 <event event="0x74" title="Scorpion" name="UTLB_I_MISS" description="UTLB i-side misses"/>
63 <event event="0x75" title="Scorpion" name="UTLB_I_ACCESS" description="UTLB i-side accesses"/>
64 <event event="0x76" title="Scorpion" name="UTLB_INV_ASID" description="UTLB invalidate by ASID"/>
65 <event event="0x77" title="Scorpion" name="UTLB_INV_MVA" description="UTLB invalidate by MVA"/>
66 <event event="0x78" title="Scorpion" name="UTLB_INV_ALL" description="UTLB invalidate all"/>
67 <event event="0x79" title="Scorpion" name="S2_HOLD_RDQ_UNAVAIL" description="S2 hold RDQ unavail"/>
68 <event event="0x7a" title="Scorpion" name="S2_HOLD" description="S2 hold"/>
69 <event event="0x7b" title="Scorpion" name="S2_HOLD_DEV_OP" description="S2 hold device op"/>
70 <event event="0x7c" title="Scorpion" name="S2_HOLD_ORDER" description="S2 hold strongly ordered op"/>
71 <event event="0x7d" title="Scorpion" name="S2_HOLD_BARRIER" description="S2 hold barrier"/>
72 <event event="0x7e" title="Scorpion" name="VIU_DUAL_CYCLE" description="Scorpion VIU dual cycle"/>
73 <event event="0x7f" title="Scorpion" name="VIU_SINGLE_CYCLE" description="Scorpion VIU single cycle"/>
74 <event event="0x80" title="Scorpion" name="VX_PIPE_WAR_STALL_CYCLES" description="Scorpion VX pipe WAR cycles"/>
75 <event event="0x81" title="Scorpion" name="VX_PIPE_WAW_STALL_CYCLES" description="Scorpion VX pipe WAW cycles"/>
76 <event event="0x82" title="Scorpion" name="VX_PIPE_RAW_STALL_CYCLES" description="Scorpion VX pipe RAW cycles"/>
77 <event event="0x83" title="Scorpion" name="VX_PIPE_LOAD_USE_STALL" description="Scorpion VX pipe load use stall"/>
78 <event event="0x84" title="Scorpion" name="VS_PIPE_WAR_STALL_CYCLES" description="Scorpion VS pipe WAR stall cycles"/>
79 <event event="0x85" title="Scorpion" name="VS_PIPE_WAW_STALL_CYCLES" description="Scorpion VS pipe WAW stall cycles"/>
80 <event event="0x86" title="Scorpion" name="VS_PIPE_RAW_STALL_CYCLES" description="Scorpion VS pipe RAW stall cycles"/>
81 <event event="0x87" title="Scorpion" name="EXCEPTIONS_INV_OPERATION" description="Scorpion invalid operation exceptions"/>
82 <event event="0x88" title="Scorpion" name="EXCEPTIONS_DIV_BY_ZERO" description="Scorpion divide by zero exceptions"/>
83 <event event="0x89" title="Scorpion" name="COND_INST_FAIL_VX_PIPE" description="Scorpion conditional instruction fail VX pipe"/>
84 <event event="0x8a" title="Scorpion" name="COND_INST_FAIL_VS_PIPE" description="Scorpion conditional instruction fail VS pipe"/>
85 <event event="0x8b" title="Scorpion" name="EXCEPTIONS_OVERFLOW" description="Scorpion overflow exceptions"/>
86 <event event="0x8c" title="Scorpion" name="EXCEPTIONS_UNDERFLOW" description="Scorpion underflow exceptions"/>
87 <event event="0x8d" title="Scorpion" name="EXCEPTIONS_DENORM" description="Scorpion denorm exceptions"/>
88 <event event="0x8e" title="ScorpionMP" name="NUM_BARRIERS" description="Barriers"/>
89 <event event="0x8f" title="ScorpionMP" name="BARRIER_CYCLES" description="Barrier cycles"/>
90 </category>
diff --git a/tools/gator/daemon/events_footer.xml b/tools/gator/daemon/events_footer.xml
new file mode 100644
index 00000000000..cd2b44665ba
--- /dev/null
+++ b/tools/gator/daemon/events_footer.xml
@@ -0,0 +1 @@
</events>
diff --git a/tools/gator/daemon/events_header.xml b/tools/gator/daemon/events_header.xml
new file mode 100644
index 00000000000..38ec4c03246
--- /dev/null
+++ b/tools/gator/daemon/events_header.xml
@@ -0,0 +1,2 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<events>
diff --git a/tools/gator/daemon/k/perf_event.3.12.h b/tools/gator/daemon/k/perf_event.3.12.h
new file mode 100644
index 00000000000..e886c48cadf
--- /dev/null
+++ b/tools/gator/daemon/k/perf_event.3.12.h
@@ -0,0 +1,792 @@
1/*
2 * Performance events:
3 *
4 * Copyright (C) 2008-2009, Thomas Gleixner <tglx@linutronix.de>
5 * Copyright (C) 2008-2011, Red Hat, Inc., Ingo Molnar
6 * Copyright (C) 2008-2011, Red Hat, Inc., Peter Zijlstra
7 *
8 * Data type definitions, declarations, prototypes.
9 *
10 * Started by: Thomas Gleixner and Ingo Molnar
11 *
12 * For licencing details see kernel-base/COPYING
13 */
14#ifndef _LINUX_PERF_EVENT_H
15#define _LINUX_PERF_EVENT_H
16
17#include <linux/types.h>
18#include <linux/ioctl.h>
19#include <asm/byteorder.h>
20
21/*
22 * User-space ABI bits:
23 */
24
25/*
26 * attr.type
27 */
28enum perf_type_id {
29 PERF_TYPE_HARDWARE = 0,
30 PERF_TYPE_SOFTWARE = 1,
31 PERF_TYPE_TRACEPOINT = 2,
32 PERF_TYPE_HW_CACHE = 3,
33 PERF_TYPE_RAW = 4,
34 PERF_TYPE_BREAKPOINT = 5,
35
36 PERF_TYPE_MAX, /* non-ABI */
37};
38
39/*
40 * Generalized performance event event_id types, used by the
41 * attr.event_id parameter of the sys_perf_event_open()
42 * syscall:
43 */
44enum perf_hw_id {
45 /*
46 * Common hardware events, generalized by the kernel:
47 */
48 PERF_COUNT_HW_CPU_CYCLES = 0,
49 PERF_COUNT_HW_INSTRUCTIONS = 1,
50 PERF_COUNT_HW_CACHE_REFERENCES = 2,
51 PERF_COUNT_HW_CACHE_MISSES = 3,
52 PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4,
53 PERF_COUNT_HW_BRANCH_MISSES = 5,
54 PERF_COUNT_HW_BUS_CYCLES = 6,
55 PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 7,
56 PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 8,
57 PERF_COUNT_HW_REF_CPU_CYCLES = 9,
58
59 PERF_COUNT_HW_MAX, /* non-ABI */
60};
61
62/*
63 * Generalized hardware cache events:
64 *
65 * { L1-D, L1-I, LLC, ITLB, DTLB, BPU, NODE } x
66 * { read, write, prefetch } x
67 * { accesses, misses }
68 */
69enum perf_hw_cache_id {
70 PERF_COUNT_HW_CACHE_L1D = 0,
71 PERF_COUNT_HW_CACHE_L1I = 1,
72 PERF_COUNT_HW_CACHE_LL = 2,
73 PERF_COUNT_HW_CACHE_DTLB = 3,
74 PERF_COUNT_HW_CACHE_ITLB = 4,
75 PERF_COUNT_HW_CACHE_BPU = 5,
76 PERF_COUNT_HW_CACHE_NODE = 6,
77
78 PERF_COUNT_HW_CACHE_MAX, /* non-ABI */
79};
80
81enum perf_hw_cache_op_id {
82 PERF_COUNT_HW_CACHE_OP_READ = 0,
83 PERF_COUNT_HW_CACHE_OP_WRITE = 1,
84 PERF_COUNT_HW_CACHE_OP_PREFETCH = 2,
85
86 PERF_COUNT_HW_CACHE_OP_MAX, /* non-ABI */
87};
88
89enum perf_hw_cache_op_result_id {
90 PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0,
91 PERF_COUNT_HW_CACHE_RESULT_MISS = 1,
92
93 PERF_COUNT_HW_CACHE_RESULT_MAX, /* non-ABI */
94};
95
96/*
97 * Special "software" events provided by the kernel, even if the hardware
98 * does not support performance events. These events measure various
99 * physical and sw events of the kernel (and allow the profiling of them as
100 * well):
101 */
102enum perf_sw_ids {
103 PERF_COUNT_SW_CPU_CLOCK = 0,
104 PERF_COUNT_SW_TASK_CLOCK = 1,
105 PERF_COUNT_SW_PAGE_FAULTS = 2,
106 PERF_COUNT_SW_CONTEXT_SWITCHES = 3,
107 PERF_COUNT_SW_CPU_MIGRATIONS = 4,
108 PERF_COUNT_SW_PAGE_FAULTS_MIN = 5,
109 PERF_COUNT_SW_PAGE_FAULTS_MAJ = 6,
110 PERF_COUNT_SW_ALIGNMENT_FAULTS = 7,
111 PERF_COUNT_SW_EMULATION_FAULTS = 8,
112 PERF_COUNT_SW_DUMMY = 9,
113
114 PERF_COUNT_SW_MAX, /* non-ABI */
115};
116
117/*
118 * Bits that can be set in attr.sample_type to request information
119 * in the overflow packets.
120 */
121enum perf_event_sample_format {
122 PERF_SAMPLE_IP = 1U << 0,
123 PERF_SAMPLE_TID = 1U << 1,
124 PERF_SAMPLE_TIME = 1U << 2,
125 PERF_SAMPLE_ADDR = 1U << 3,
126 PERF_SAMPLE_READ = 1U << 4,
127 PERF_SAMPLE_CALLCHAIN = 1U << 5,
128 PERF_SAMPLE_ID = 1U << 6,
129 PERF_SAMPLE_CPU = 1U << 7,
130 PERF_SAMPLE_PERIOD = 1U << 8,
131 PERF_SAMPLE_STREAM_ID = 1U << 9,
132 PERF_SAMPLE_RAW = 1U << 10,
133 PERF_SAMPLE_BRANCH_STACK = 1U << 11,
134 PERF_SAMPLE_REGS_USER = 1U << 12,
135 PERF_SAMPLE_STACK_USER = 1U << 13,
136 PERF_SAMPLE_WEIGHT = 1U << 14,
137 PERF_SAMPLE_DATA_SRC = 1U << 15,
138 PERF_SAMPLE_IDENTIFIER = 1U << 16,
139
140 PERF_SAMPLE_MAX = 1U << 17, /* non-ABI */
141};
142
143/*
144 * values to program into branch_sample_type when PERF_SAMPLE_BRANCH is set
145 *
146 * If the user does not pass priv level information via branch_sample_type,
147 * the kernel uses the event's priv level. Branch and event priv levels do
148 * not have to match. Branch priv level is checked for permissions.
149 *
150 * The branch types can be combined, however BRANCH_ANY covers all types
151 * of branches and therefore it supersedes all the other types.
152 */
153enum perf_branch_sample_type {
154 PERF_SAMPLE_BRANCH_USER = 1U << 0, /* user branches */
155 PERF_SAMPLE_BRANCH_KERNEL = 1U << 1, /* kernel branches */
156 PERF_SAMPLE_BRANCH_HV = 1U << 2, /* hypervisor branches */
157
158 PERF_SAMPLE_BRANCH_ANY = 1U << 3, /* any branch types */
159 PERF_SAMPLE_BRANCH_ANY_CALL = 1U << 4, /* any call branch */
160 PERF_SAMPLE_BRANCH_ANY_RETURN = 1U << 5, /* any return branch */
161 PERF_SAMPLE_BRANCH_IND_CALL = 1U << 6, /* indirect calls */
162 PERF_SAMPLE_BRANCH_ABORT_TX = 1U << 7, /* transaction aborts */
163 PERF_SAMPLE_BRANCH_IN_TX = 1U << 8, /* in transaction */
164 PERF_SAMPLE_BRANCH_NO_TX = 1U << 9, /* not in transaction */
165
166 PERF_SAMPLE_BRANCH_MAX = 1U << 10, /* non-ABI */
167};
168
169#define PERF_SAMPLE_BRANCH_PLM_ALL \
170 (PERF_SAMPLE_BRANCH_USER|\
171 PERF_SAMPLE_BRANCH_KERNEL|\
172 PERF_SAMPLE_BRANCH_HV)
173
174/*
175 * Values to determine ABI of the registers dump.
176 */
177enum perf_sample_regs_abi {
178 PERF_SAMPLE_REGS_ABI_NONE = 0,
179 PERF_SAMPLE_REGS_ABI_32 = 1,
180 PERF_SAMPLE_REGS_ABI_64 = 2,
181};
182
183/*
184 * The format of the data returned by read() on a perf event fd,
185 * as specified by attr.read_format:
186 *
187 * struct read_format {
188 * { u64 value;
189 * { u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
190 * { u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
191 * { u64 id; } && PERF_FORMAT_ID
192 * } && !PERF_FORMAT_GROUP
193 *
194 * { u64 nr;
195 * { u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
196 * { u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
197 * { u64 value;
198 * { u64 id; } && PERF_FORMAT_ID
199 * } cntr[nr];
200 * } && PERF_FORMAT_GROUP
201 * };
202 */
203enum perf_event_read_format {
204 PERF_FORMAT_TOTAL_TIME_ENABLED = 1U << 0,
205 PERF_FORMAT_TOTAL_TIME_RUNNING = 1U << 1,
206 PERF_FORMAT_ID = 1U << 2,
207 PERF_FORMAT_GROUP = 1U << 3,
208
209 PERF_FORMAT_MAX = 1U << 4, /* non-ABI */
210};
211
212#define PERF_ATTR_SIZE_VER0 64 /* sizeof first published struct */
213#define PERF_ATTR_SIZE_VER1 72 /* add: config2 */
214#define PERF_ATTR_SIZE_VER2 80 /* add: branch_sample_type */
215#define PERF_ATTR_SIZE_VER3 96 /* add: sample_regs_user */
216 /* add: sample_stack_user */
217
218/*
219 * Hardware event_id to monitor via a performance monitoring event:
220 */
221struct perf_event_attr {
222
223 /*
224 * Major type: hardware/software/tracepoint/etc.
225 */
226 __u32 type;
227
228 /*
229 * Size of the attr structure, for fwd/bwd compat.
230 */
231 __u32 size;
232
233 /*
234 * Type specific configuration information.
235 */
236 __u64 config;
237
238 union {
239 __u64 sample_period;
240 __u64 sample_freq;
241 };
242
243 __u64 sample_type;
244 __u64 read_format;
245
246 __u64 disabled : 1, /* off by default */
247 inherit : 1, /* children inherit it */
248 pinned : 1, /* must always be on PMU */
249 exclusive : 1, /* only group on PMU */
250 exclude_user : 1, /* don't count user */
251 exclude_kernel : 1, /* ditto kernel */
252 exclude_hv : 1, /* ditto hypervisor */
253 exclude_idle : 1, /* don't count when idle */
254 mmap : 1, /* include mmap data */
255 comm : 1, /* include comm data */
256 freq : 1, /* use freq, not period */
257 inherit_stat : 1, /* per task counts */
258 enable_on_exec : 1, /* next exec enables */
259 task : 1, /* trace fork/exit */
260 watermark : 1, /* wakeup_watermark */
261 /*
262 * precise_ip:
263 *
264 * 0 - SAMPLE_IP can have arbitrary skid
265 * 1 - SAMPLE_IP must have constant skid
266 * 2 - SAMPLE_IP requested to have 0 skid
267 * 3 - SAMPLE_IP must have 0 skid
268 *
269 * See also PERF_RECORD_MISC_EXACT_IP
270 */
271 precise_ip : 2, /* skid constraint */
272 mmap_data : 1, /* non-exec mmap data */
273 sample_id_all : 1, /* sample_type all events */
274
275 exclude_host : 1, /* don't count in host */
276 exclude_guest : 1, /* don't count in guest */
277
278 exclude_callchain_kernel : 1, /* exclude kernel callchains */
279 exclude_callchain_user : 1, /* exclude user callchains */
280 mmap2 : 1, /* include mmap with inode data */
281
282 __reserved_1 : 40;
283
284 union {
285 __u32 wakeup_events; /* wakeup every n events */
286 __u32 wakeup_watermark; /* bytes before wakeup */
287 };
288
289 __u32 bp_type;
290 union {
291 __u64 bp_addr;
292 __u64 config1; /* extension of config */
293 };
294 union {
295 __u64 bp_len;
296 __u64 config2; /* extension of config1 */
297 };
298 __u64 branch_sample_type; /* enum perf_branch_sample_type */
299
300 /*
301 * Defines set of user regs to dump on samples.
302 * See asm/perf_regs.h for details.
303 */
304 __u64 sample_regs_user;
305
306 /*
307 * Defines size of the user stack to dump on samples.
308 */
309 __u32 sample_stack_user;
310
311 /* Align to u64. */
312 __u32 __reserved_2;
313};
314
315#define perf_flags(attr) (*(&(attr)->read_format + 1))
316
317/*
318 * Ioctls that can be done on a perf event fd:
319 */
320#define PERF_EVENT_IOC_ENABLE _IO ('$', 0)
321#define PERF_EVENT_IOC_DISABLE _IO ('$', 1)
322#define PERF_EVENT_IOC_REFRESH _IO ('$', 2)
323#define PERF_EVENT_IOC_RESET _IO ('$', 3)
324#define PERF_EVENT_IOC_PERIOD _IOW('$', 4, __u64)
325#define PERF_EVENT_IOC_SET_OUTPUT _IO ('$', 5)
326#define PERF_EVENT_IOC_SET_FILTER _IOW('$', 6, char *)
327#define PERF_EVENT_IOC_ID _IOR('$', 7, __u64 *)
328
329enum perf_event_ioc_flags {
330 PERF_IOC_FLAG_GROUP = 1U << 0,
331};
332
333/*
334 * Structure of the page that can be mapped via mmap
335 */
336struct perf_event_mmap_page {
337 __u32 version; /* version number of this structure */
338 __u32 compat_version; /* lowest version this is compat with */
339
340 /*
341 * Bits needed to read the hw events in user-space.
342 *
343 * u32 seq, time_mult, time_shift, idx, width;
344 * u64 count, enabled, running;
345 * u64 cyc, time_offset;
346 * s64 pmc = 0;
347 *
348 * do {
349 * seq = pc->lock;
350 * barrier()
351 *
352 * enabled = pc->time_enabled;
353 * running = pc->time_running;
354 *
355 * if (pc->cap_usr_time && enabled != running) {
356 * cyc = rdtsc();
357 * time_offset = pc->time_offset;
358 * time_mult = pc->time_mult;
359 * time_shift = pc->time_shift;
360 * }
361 *
362 * idx = pc->index;
363 * count = pc->offset;
364 * if (pc->cap_usr_rdpmc && idx) {
365 * width = pc->pmc_width;
366 * pmc = rdpmc(idx - 1);
367 * }
368 *
369 * barrier();
370 * } while (pc->lock != seq);
371 *
372 * NOTE: for obvious reason this only works on self-monitoring
373 * processes.
374 */
375 __u32 lock; /* seqlock for synchronization */
376 __u32 index; /* hardware event identifier */
377 __s64 offset; /* add to hardware event value */
378 __u64 time_enabled; /* time event active */
379 __u64 time_running; /* time event on cpu */
380 union {
381 __u64 capabilities;
382 struct {
383 __u64 cap_bit0 : 1, /* Always 0, deprecated, see commit 860f085b74e9 */
384 cap_bit0_is_deprecated : 1, /* Always 1, signals that bit 0 is zero */
385
386 cap_user_rdpmc : 1, /* The RDPMC instruction can be used to read counts */
387 cap_user_time : 1, /* The time_* fields are used */
388 cap_user_time_zero : 1, /* The time_zero field is used */
389 cap_____res : 59;
390 };
391 };
392
393 /*
394 * If cap_usr_rdpmc this field provides the bit-width of the value
395 * read using the rdpmc() or equivalent instruction. This can be used
396 * to sign extend the result like:
397 *
398 * pmc <<= 64 - width;
399 * pmc >>= 64 - width; // signed shift right
400 * count += pmc;
401 */
402 __u16 pmc_width;
403
404 /*
405 * If cap_usr_time the below fields can be used to compute the time
406 * delta since time_enabled (in ns) using rdtsc or similar.
407 *
408 * u64 quot, rem;
409 * u64 delta;
410 *
411 * quot = (cyc >> time_shift);
412 * rem = cyc & ((1 << time_shift) - 1);
413 * delta = time_offset + quot * time_mult +
414 * ((rem * time_mult) >> time_shift);
415 *
416 * Where time_offset,time_mult,time_shift and cyc are read in the
417 * seqcount loop described above. This delta can then be added to
418 * enabled and possible running (if idx), improving the scaling:
419 *
420 * enabled += delta;
421 * if (idx)
422 * running += delta;
423 *
424 * quot = count / running;
425 * rem = count % running;
426 * count = quot * enabled + (rem * enabled) / running;
427 */
428 __u16 time_shift;
429 __u32 time_mult;
430 __u64 time_offset;
431 /*
432 * If cap_usr_time_zero, the hardware clock (e.g. TSC) can be calculated
433 * from sample timestamps.
434 *
435 * time = timestamp - time_zero;
436 * quot = time / time_mult;
437 * rem = time % time_mult;
438 * cyc = (quot << time_shift) + (rem << time_shift) / time_mult;
439 *
440 * And vice versa:
441 *
442 * quot = cyc >> time_shift;
443 * rem = cyc & ((1 << time_shift) - 1);
444 * timestamp = time_zero + quot * time_mult +
445 * ((rem * time_mult) >> time_shift);
446 */
447 __u64 time_zero;
448 __u32 size; /* Header size up to __reserved[] fields. */
449
450 /*
451 * Hole for extension of the self monitor capabilities
452 */
453
454 __u8 __reserved[118*8+4]; /* align to 1k. */
455
456 /*
457 * Control data for the mmap() data buffer.
458 *
459 * User-space reading the @data_head value should issue an smp_rmb(),
460 * after reading this value.
461 *
462 * When the mapping is PROT_WRITE the @data_tail value should be
463 * written by userspace to reflect the last read data, after issueing
464 * an smp_mb() to separate the data read from the ->data_tail store.
465 * In this case the kernel will not over-write unread data.
466 *
467 * See perf_output_put_handle() for the data ordering.
468 */
469 __u64 data_head; /* head in the data section */
470 __u64 data_tail; /* user-space written tail */
471};
472
473#define PERF_RECORD_MISC_CPUMODE_MASK (7 << 0)
474#define PERF_RECORD_MISC_CPUMODE_UNKNOWN (0 << 0)
475#define PERF_RECORD_MISC_KERNEL (1 << 0)
476#define PERF_RECORD_MISC_USER (2 << 0)
477#define PERF_RECORD_MISC_HYPERVISOR (3 << 0)
478#define PERF_RECORD_MISC_GUEST_KERNEL (4 << 0)
479#define PERF_RECORD_MISC_GUEST_USER (5 << 0)
480
481#define PERF_RECORD_MISC_MMAP_DATA (1 << 13)
482/*
483 * Indicates that the content of PERF_SAMPLE_IP points to
484 * the actual instruction that triggered the event. See also
485 * perf_event_attr::precise_ip.
486 */
487#define PERF_RECORD_MISC_EXACT_IP (1 << 14)
488/*
489 * Reserve the last bit to indicate some extended misc field
490 */
491#define PERF_RECORD_MISC_EXT_RESERVED (1 << 15)
492
493struct perf_event_header {
494 __u32 type;
495 __u16 misc;
496 __u16 size;
497};
498
499enum perf_event_type {
500
501 /*
502 * If perf_event_attr.sample_id_all is set then all event types will
503 * have the sample_type selected fields related to where/when
504 * (identity) an event took place (TID, TIME, ID, STREAM_ID, CPU,
505 * IDENTIFIER) described in PERF_RECORD_SAMPLE below, it will be stashed
506 * just after the perf_event_header and the fields already present for
507 * the existing fields, i.e. at the end of the payload. That way a newer
508 * perf.data file will be supported by older perf tools, with these new
509 * optional fields being ignored.
510 *
511 * struct sample_id {
512 * { u32 pid, tid; } && PERF_SAMPLE_TID
513 * { u64 time; } && PERF_SAMPLE_TIME
514 * { u64 id; } && PERF_SAMPLE_ID
515 * { u64 stream_id;} && PERF_SAMPLE_STREAM_ID
516 * { u32 cpu, res; } && PERF_SAMPLE_CPU
517 * { u64 id; } && PERF_SAMPLE_IDENTIFIER
518 * } && perf_event_attr::sample_id_all
519 *
520 * Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID. The
521 * advantage of PERF_SAMPLE_IDENTIFIER is that its position is fixed
522 * relative to header.size.
523 */
524
525 /*
526 * The MMAP events record the PROT_EXEC mappings so that we can
527 * correlate userspace IPs to code. They have the following structure:
528 *
529 * struct {
530 * struct perf_event_header header;
531 *
532 * u32 pid, tid;
533 * u64 addr;
534 * u64 len;
535 * u64 pgoff;
536 * char filename[];
537 * struct sample_id sample_id;
538 * };
539 */
540 PERF_RECORD_MMAP = 1,
541
542 /*
543 * struct {
544 * struct perf_event_header header;
545 * u64 id;
546 * u64 lost;
547 * struct sample_id sample_id;
548 * };
549 */
550 PERF_RECORD_LOST = 2,
551
552 /*
553 * struct {
554 * struct perf_event_header header;
555 *
556 * u32 pid, tid;
557 * char comm[];
558 * struct sample_id sample_id;
559 * };
560 */
561 PERF_RECORD_COMM = 3,
562
563 /*
564 * struct {
565 * struct perf_event_header header;
566 * u32 pid, ppid;
567 * u32 tid, ptid;
568 * u64 time;
569 * struct sample_id sample_id;
570 * };
571 */
572 PERF_RECORD_EXIT = 4,
573
574 /*
575 * struct {
576 * struct perf_event_header header;
577 * u64 time;
578 * u64 id;
579 * u64 stream_id;
580 * struct sample_id sample_id;
581 * };
582 */
583 PERF_RECORD_THROTTLE = 5,
584 PERF_RECORD_UNTHROTTLE = 6,
585
586 /*
587 * struct {
588 * struct perf_event_header header;
589 * u32 pid, ppid;
590 * u32 tid, ptid;
591 * u64 time;
592 * struct sample_id sample_id;
593 * };
594 */
595 PERF_RECORD_FORK = 7,
596
597 /*
598 * struct {
599 * struct perf_event_header header;
600 * u32 pid, tid;
601 *
602 * struct read_format values;
603 * struct sample_id sample_id;
604 * };
605 */
606 PERF_RECORD_READ = 8,
607
608 /*
609 * struct {
610 * struct perf_event_header header;
611 *
612 * #
613 * # Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID.
614 * # The advantage of PERF_SAMPLE_IDENTIFIER is that its position
615 * # is fixed relative to header.
616 * #
617 *
618 * { u64 id; } && PERF_SAMPLE_IDENTIFIER
619 * { u64 ip; } && PERF_SAMPLE_IP
620 * { u32 pid, tid; } && PERF_SAMPLE_TID
621 * { u64 time; } && PERF_SAMPLE_TIME
622 * { u64 addr; } && PERF_SAMPLE_ADDR
623 * { u64 id; } && PERF_SAMPLE_ID
624 * { u64 stream_id;} && PERF_SAMPLE_STREAM_ID
625 * { u32 cpu, res; } && PERF_SAMPLE_CPU
626 * { u64 period; } && PERF_SAMPLE_PERIOD
627 *
628 * { struct read_format values; } && PERF_SAMPLE_READ
629 *
630 * { u64 nr,
631 * u64 ips[nr]; } && PERF_SAMPLE_CALLCHAIN
632 *
633 * #
634 * # The RAW record below is opaque data wrt the ABI
635 * #
636 * # That is, the ABI doesn't make any promises wrt to
637 * # the stability of its content, it may vary depending
638 * # on event, hardware, kernel version and phase of
639 * # the moon.
640 * #
641 * # In other words, PERF_SAMPLE_RAW contents are not an ABI.
642 * #
643 *
644 * { u32 size;
645 * char data[size];}&& PERF_SAMPLE_RAW
646 *
647 * { u64 nr;
648 * { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK
649 *
650 * { u64 abi; # enum perf_sample_regs_abi
651 * u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER
652 *
653 * { u64 size;
654 * char data[size];
655 * u64 dyn_size; } && PERF_SAMPLE_STACK_USER
656 *
657 * { u64 weight; } && PERF_SAMPLE_WEIGHT
658 * { u64 data_src; } && PERF_SAMPLE_DATA_SRC
659 * };
660 */
661 PERF_RECORD_SAMPLE = 9,
662
663 /*
664 * The MMAP2 records are an augmented version of MMAP, they add
665 * maj, min, ino numbers to be used to uniquely identify each mapping
666 *
667 * struct {
668 * struct perf_event_header header;
669 *
670 * u32 pid, tid;
671 * u64 addr;
672 * u64 len;
673 * u64 pgoff;
674 * u32 maj;
675 * u32 min;
676 * u64 ino;
677 * u64 ino_generation;
678 * char filename[];
679 * struct sample_id sample_id;
680 * };
681 */
682 PERF_RECORD_MMAP2 = 10,
683
684 PERF_RECORD_MAX, /* non-ABI */
685};
686
687#define PERF_MAX_STACK_DEPTH 127
688
689enum perf_callchain_context {
690 PERF_CONTEXT_HV = (__u64)-32,
691 PERF_CONTEXT_KERNEL = (__u64)-128,
692 PERF_CONTEXT_USER = (__u64)-512,
693
694 PERF_CONTEXT_GUEST = (__u64)-2048,
695 PERF_CONTEXT_GUEST_KERNEL = (__u64)-2176,
696 PERF_CONTEXT_GUEST_USER = (__u64)-2560,
697
698 PERF_CONTEXT_MAX = (__u64)-4095,
699};
700
701#define PERF_FLAG_FD_NO_GROUP (1U << 0)
702#define PERF_FLAG_FD_OUTPUT (1U << 1)
703#define PERF_FLAG_PID_CGROUP (1U << 2) /* pid=cgroup id, per-cpu mode only */
704
705union perf_mem_data_src {
706 __u64 val;
707 struct {
708 __u64 mem_op:5, /* type of opcode */
709 mem_lvl:14, /* memory hierarchy level */
710 mem_snoop:5, /* snoop mode */
711 mem_lock:2, /* lock instr */
712 mem_dtlb:7, /* tlb access */
713 mem_rsvd:31;
714 };
715};
716
717/* type of opcode (load/store/prefetch,code) */
718#define PERF_MEM_OP_NA 0x01 /* not available */
719#define PERF_MEM_OP_LOAD 0x02 /* load instruction */
720#define PERF_MEM_OP_STORE 0x04 /* store instruction */
721#define PERF_MEM_OP_PFETCH 0x08 /* prefetch */
722#define PERF_MEM_OP_EXEC 0x10 /* code (execution) */
723#define PERF_MEM_OP_SHIFT 0
724
725/* memory hierarchy (memory level, hit or miss) */
726#define PERF_MEM_LVL_NA 0x01 /* not available */
727#define PERF_MEM_LVL_HIT 0x02 /* hit level */
728#define PERF_MEM_LVL_MISS 0x04 /* miss level */
729#define PERF_MEM_LVL_L1 0x08 /* L1 */
730#define PERF_MEM_LVL_LFB 0x10 /* Line Fill Buffer */
731#define PERF_MEM_LVL_L2 0x20 /* L2 */
732#define PERF_MEM_LVL_L3 0x40 /* L3 */
733#define PERF_MEM_LVL_LOC_RAM 0x80 /* Local DRAM */
734#define PERF_MEM_LVL_REM_RAM1 0x100 /* Remote DRAM (1 hop) */
735#define PERF_MEM_LVL_REM_RAM2 0x200 /* Remote DRAM (2 hops) */
736#define PERF_MEM_LVL_REM_CCE1 0x400 /* Remote Cache (1 hop) */
737#define PERF_MEM_LVL_REM_CCE2 0x800 /* Remote Cache (2 hops) */
738#define PERF_MEM_LVL_IO 0x1000 /* I/O memory */
739#define PERF_MEM_LVL_UNC 0x2000 /* Uncached memory */
740#define PERF_MEM_LVL_SHIFT 5
741
742/* snoop mode */
743#define PERF_MEM_SNOOP_NA 0x01 /* not available */
744#define PERF_MEM_SNOOP_NONE 0x02 /* no snoop */
745#define PERF_MEM_SNOOP_HIT 0x04 /* snoop hit */
746#define PERF_MEM_SNOOP_MISS 0x08 /* snoop miss */
747#define PERF_MEM_SNOOP_HITM 0x10 /* snoop hit modified */
748#define PERF_MEM_SNOOP_SHIFT 19
749
750/* locked instruction */
751#define PERF_MEM_LOCK_NA 0x01 /* not available */
752#define PERF_MEM_LOCK_LOCKED 0x02 /* locked transaction */
753#define PERF_MEM_LOCK_SHIFT 24
754
755/* TLB access */
756#define PERF_MEM_TLB_NA 0x01 /* not available */
757#define PERF_MEM_TLB_HIT 0x02 /* hit level */
758#define PERF_MEM_TLB_MISS 0x04 /* miss level */
759#define PERF_MEM_TLB_L1 0x08 /* L1 */
760#define PERF_MEM_TLB_L2 0x10 /* L2 */
761#define PERF_MEM_TLB_WK 0x20 /* Hardware Walker*/
762#define PERF_MEM_TLB_OS 0x40 /* OS fault handler */
763#define PERF_MEM_TLB_SHIFT 26
764
765#define PERF_MEM_S(a, s) \
766 (((u64)PERF_MEM_##a##_##s) << PERF_MEM_##a##_SHIFT)
767
768/*
769 * single taken branch record layout:
770 *
771 * from: source instruction (may not always be a branch insn)
772 * to: branch target
773 * mispred: branch target was mispredicted
774 * predicted: branch target was predicted
775 *
776 * support for mispred, predicted is optional. In case it
777 * is not supported mispred = predicted = 0.
778 *
779 * in_tx: running in a hardware transaction
780 * abort: aborting a hardware transaction
781 */
782struct perf_branch_entry {
783 __u64 from;
784 __u64 to;
785 __u64 mispred:1, /* target mispredicted */
786 predicted:1,/* target predicted */
787 in_tx:1, /* in transaction */
788 abort:1, /* transaction abort */
789 reserved:60;
790};
791
792#endif /* _LINUX_PERF_EVENT_H */
diff --git a/tools/gator/daemon/k/perf_event.h b/tools/gator/daemon/k/perf_event.h
new file mode 120000
index 00000000000..e5dff8c21ef
--- /dev/null
+++ b/tools/gator/daemon/k/perf_event.h
@@ -0,0 +1 @@
perf_event.3.12.h \ No newline at end of file
diff --git a/tools/gator/daemon/libsensors/COPYING.LGPL b/tools/gator/daemon/libsensors/COPYING.LGPL
new file mode 100644
index 00000000000..4362b49151d
--- /dev/null
+++ b/tools/gator/daemon/libsensors/COPYING.LGPL
@@ -0,0 +1,502 @@
1 GNU LESSER GENERAL PUBLIC LICENSE
2 Version 2.1, February 1999
3
4 Copyright (C) 1991, 1999 Free Software Foundation, Inc.
5 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 Everyone is permitted to copy and distribute verbatim copies
7 of this license document, but changing it is not allowed.
8
9[This is the first released version of the Lesser GPL. It also counts
10 as the successor of the GNU Library Public License, version 2, hence
11 the version number 2.1.]
12
13 Preamble
14
15 The licenses for most software are designed to take away your
16freedom to share and change it. By contrast, the GNU General Public
17Licenses are intended to guarantee your freedom to share and change
18free software--to make sure the software is free for all its users.
19
20 This license, the Lesser General Public License, applies to some
21specially designated software packages--typically libraries--of the
22Free Software Foundation and other authors who decide to use it. You
23can use it too, but we suggest you first think carefully about whether
24this license or the ordinary General Public License is the better
25strategy to use in any particular case, based on the explanations below.
26
27 When we speak of free software, we are referring to freedom of use,
28not price. Our General Public Licenses are designed to make sure that
29you have the freedom to distribute copies of free software (and charge
30for this service if you wish); that you receive source code or can get
31it if you want it; that you can change the software and use pieces of
32it in new free programs; and that you are informed that you can do
33these things.
34
35 To protect your rights, we need to make restrictions that forbid
36distributors to deny you these rights or to ask you to surrender these
37rights. These restrictions translate to certain responsibilities for
38you if you distribute copies of the library or if you modify it.
39
40 For example, if you distribute copies of the library, whether gratis
41or for a fee, you must give the recipients all the rights that we gave
42you. You must make sure that they, too, receive or can get the source
43code. If you link other code with the library, you must provide
44complete object files to the recipients, so that they can relink them
45with the library after making changes to the library and recompiling
46it. And you must show them these terms so they know their rights.
47
48 We protect your rights with a two-step method: (1) we copyright the
49library, and (2) we offer you this license, which gives you legal
50permission to copy, distribute and/or modify the library.
51
52 To protect each distributor, we want to make it very clear that
53there is no warranty for the free library. Also, if the library is
54modified by someone else and passed on, the recipients should know
55that what they have is not the original version, so that the original
56author's reputation will not be affected by problems that might be
57introduced by others.
58
59 Finally, software patents pose a constant threat to the existence of
60any free program. We wish to make sure that a company cannot
61effectively restrict the users of a free program by obtaining a
62restrictive license from a patent holder. Therefore, we insist that
63any patent license obtained for a version of the library must be
64consistent with the full freedom of use specified in this license.
65
66 Most GNU software, including some libraries, is covered by the
67ordinary GNU General Public License. This license, the GNU Lesser
68General Public License, applies to certain designated libraries, and
69is quite different from the ordinary General Public License. We use
70this license for certain libraries in order to permit linking those
71libraries into non-free programs.
72
73 When a program is linked with a library, whether statically or using
74a shared library, the combination of the two is legally speaking a
75combined work, a derivative of the original library. The ordinary
76General Public License therefore permits such linking only if the
77entire combination fits its criteria of freedom. The Lesser General
78Public License permits more lax criteria for linking other code with
79the library.
80
81 We call this license the "Lesser" General Public License because it
82does Less to protect the user's freedom than the ordinary General
83Public License. It also provides other free software developers Less
84of an advantage over competing non-free programs. These disadvantages
85are the reason we use the ordinary General Public License for many
86libraries. However, the Lesser license provides advantages in certain
87special circumstances.
88
89 For example, on rare occasions, there may be a special need to
90encourage the widest possible use of a certain library, so that it becomes
91a de-facto standard. To achieve this, non-free programs must be
92allowed to use the library. A more frequent case is that a free
93library does the same job as widely used non-free libraries. In this
94case, there is little to gain by limiting the free library to free
95software only, so we use the Lesser General Public License.
96
97 In other cases, permission to use a particular library in non-free
98programs enables a greater number of people to use a large body of
99free software. For example, permission to use the GNU C Library in
100non-free programs enables many more people to use the whole GNU
101operating system, as well as its variant, the GNU/Linux operating
102system.
103
104 Although the Lesser General Public License is Less protective of the
105users' freedom, it does ensure that the user of a program that is
106linked with the Library has the freedom and the wherewithal to run
107that program using a modified version of the Library.
108
109 The precise terms and conditions for copying, distribution and
110modification follow. Pay close attention to the difference between a
111"work based on the library" and a "work that uses the library". The
112former contains code derived from the library, whereas the latter must
113be combined with the library in order to run.
114
115 GNU LESSER GENERAL PUBLIC LICENSE
116 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
117
118 0. This License Agreement applies to any software library or other
119program which contains a notice placed by the copyright holder or
120other authorized party saying it may be distributed under the terms of
121this Lesser General Public License (also called "this License").
122Each licensee is addressed as "you".
123
124 A "library" means a collection of software functions and/or data
125prepared so as to be conveniently linked with application programs
126(which use some of those functions and data) to form executables.
127
128 The "Library", below, refers to any such software library or work
129which has been distributed under these terms. A "work based on the
130Library" means either the Library or any derivative work under
131copyright law: that is to say, a work containing the Library or a
132portion of it, either verbatim or with modifications and/or translated
133straightforwardly into another language. (Hereinafter, translation is
134included without limitation in the term "modification".)
135
136 "Source code" for a work means the preferred form of the work for
137making modifications to it. For a library, complete source code means
138all the source code for all modules it contains, plus any associated
139interface definition files, plus the scripts used to control compilation
140and installation of the library.
141
142 Activities other than copying, distribution and modification are not
143covered by this License; they are outside its scope. The act of
144running a program using the Library is not restricted, and output from
145such a program is covered only if its contents constitute a work based
146on the Library (independent of the use of the Library in a tool for
147writing it). Whether that is true depends on what the Library does
148and what the program that uses the Library does.
149
150 1. You may copy and distribute verbatim copies of the Library's
151complete source code as you receive it, in any medium, provided that
152you conspicuously and appropriately publish on each copy an
153appropriate copyright notice and disclaimer of warranty; keep intact
154all the notices that refer to this License and to the absence of any
155warranty; and distribute a copy of this License along with the
156Library.
157
158 You may charge a fee for the physical act of transferring a copy,
159and you may at your option offer warranty protection in exchange for a
160fee.
161
162 2. You may modify your copy or copies of the Library or any portion
163of it, thus forming a work based on the Library, and copy and
164distribute such modifications or work under the terms of Section 1
165above, provided that you also meet all of these conditions:
166
167 a) The modified work must itself be a software library.
168
169 b) You must cause the files modified to carry prominent notices
170 stating that you changed the files and the date of any change.
171
172 c) You must cause the whole of the work to be licensed at no
173 charge to all third parties under the terms of this License.
174
175 d) If a facility in the modified Library refers to a function or a
176 table of data to be supplied by an application program that uses
177 the facility, other than as an argument passed when the facility
178 is invoked, then you must make a good faith effort to ensure that,
179 in the event an application does not supply such function or
180 table, the facility still operates, and performs whatever part of
181 its purpose remains meaningful.
182
183 (For example, a function in a library to compute square roots has
184 a purpose that is entirely well-defined independent of the
185 application. Therefore, Subsection 2d requires that any
186 application-supplied function or table used by this function must
187 be optional: if the application does not supply it, the square
188 root function must still compute square roots.)
189
190These requirements apply to the modified work as a whole. If
191identifiable sections of that work are not derived from the Library,
192and can be reasonably considered independent and separate works in
193themselves, then this License, and its terms, do not apply to those
194sections when you distribute them as separate works. But when you
195distribute the same sections as part of a whole which is a work based
196on the Library, the distribution of the whole must be on the terms of
197this License, whose permissions for other licensees extend to the
198entire whole, and thus to each and every part regardless of who wrote
199it.
200
201Thus, it is not the intent of this section to claim rights or contest
202your rights to work written entirely by you; rather, the intent is to
203exercise the right to control the distribution of derivative or
204collective works based on the Library.
205
206In addition, mere aggregation of another work not based on the Library
207with the Library (or with a work based on the Library) on a volume of
208a storage or distribution medium does not bring the other work under
209the scope of this License.
210
211 3. You may opt to apply the terms of the ordinary GNU General Public
212License instead of this License to a given copy of the Library. To do
213this, you must alter all the notices that refer to this License, so
214that they refer to the ordinary GNU General Public License, version 2,
215instead of to this License. (If a newer version than version 2 of the
216ordinary GNU General Public License has appeared, then you can specify
217that version instead if you wish.) Do not make any other change in
218these notices.
219
220 Once this change is made in a given copy, it is irreversible for
221that copy, so the ordinary GNU General Public License applies to all
222subsequent copies and derivative works made from that copy.
223
224 This option is useful when you wish to copy part of the code of
225the Library into a program that is not a library.
226
227 4. You may copy and distribute the Library (or a portion or
228derivative of it, under Section 2) in object code or executable form
229under the terms of Sections 1 and 2 above provided that you accompany
230it with the complete corresponding machine-readable source code, which
231must be distributed under the terms of Sections 1 and 2 above on a
232medium customarily used for software interchange.
233
234 If distribution of object code is made by offering access to copy
235from a designated place, then offering equivalent access to copy the
236source code from the same place satisfies the requirement to
237distribute the source code, even though third parties are not
238compelled to copy the source along with the object code.
239
240 5. A program that contains no derivative of any portion of the
241Library, but is designed to work with the Library by being compiled or
242linked with it, is called a "work that uses the Library". Such a
243work, in isolation, is not a derivative work of the Library, and
244therefore falls outside the scope of this License.
245
246 However, linking a "work that uses the Library" with the Library
247creates an executable that is a derivative of the Library (because it
248contains portions of the Library), rather than a "work that uses the
249library". The executable is therefore covered by this License.
250Section 6 states terms for distribution of such executables.
251
252 When a "work that uses the Library" uses material from a header file
253that is part of the Library, the object code for the work may be a
254derivative work of the Library even though the source code is not.
255Whether this is true is especially significant if the work can be
256linked without the Library, or if the work is itself a library. The
257threshold for this to be true is not precisely defined by law.
258
259 If such an object file uses only numerical parameters, data
260structure layouts and accessors, and small macros and small inline
261functions (ten lines or less in length), then the use of the object
262file is unrestricted, regardless of whether it is legally a derivative
263work. (Executables containing this object code plus portions of the
264Library will still fall under Section 6.)
265
266 Otherwise, if the work is a derivative of the Library, you may
267distribute the object code for the work under the terms of Section 6.
268Any executables containing that work also fall under Section 6,
269whether or not they are linked directly with the Library itself.
270
271 6. As an exception to the Sections above, you may also combine or
272link a "work that uses the Library" with the Library to produce a
273work containing portions of the Library, and distribute that work
274under terms of your choice, provided that the terms permit
275modification of the work for the customer's own use and reverse
276engineering for debugging such modifications.
277
278 You must give prominent notice with each copy of the work that the
279Library is used in it and that the Library and its use are covered by
280this License. You must supply a copy of this License. If the work
281during execution displays copyright notices, you must include the
282copyright notice for the Library among them, as well as a reference
283directing the user to the copy of this License. Also, you must do one
284of these things:
285
286 a) Accompany the work with the complete corresponding
287 machine-readable source code for the Library including whatever
288 changes were used in the work (which must be distributed under
289 Sections 1 and 2 above); and, if the work is an executable linked
290 with the Library, with the complete machine-readable "work that
291 uses the Library", as object code and/or source code, so that the
292 user can modify the Library and then relink to produce a modified
293 executable containing the modified Library. (It is understood
294 that the user who changes the contents of definitions files in the
295 Library will not necessarily be able to recompile the application
296 to use the modified definitions.)
297
298 b) Use a suitable shared library mechanism for linking with the
299 Library. A suitable mechanism is one that (1) uses at run time a
300 copy of the library already present on the user's computer system,
301 rather than copying library functions into the executable, and (2)
302 will operate properly with a modified version of the library, if
303 the user installs one, as long as the modified version is
304 interface-compatible with the version that the work was made with.
305
306 c) Accompany the work with a written offer, valid for at
307 least three years, to give the same user the materials
308 specified in Subsection 6a, above, for a charge no more
309 than the cost of performing this distribution.
310
311 d) If distribution of the work is made by offering access to copy
312 from a designated place, offer equivalent access to copy the above
313 specified materials from the same place.
314
315 e) Verify that the user has already received a copy of these
316 materials or that you have already sent this user a copy.
317
318 For an executable, the required form of the "work that uses the
319Library" must include any data and utility programs needed for
320reproducing the executable from it. However, as a special exception,
321the materials to be distributed need not include anything that is
322normally distributed (in either source or binary form) with the major
323components (compiler, kernel, and so on) of the operating system on
324which the executable runs, unless that component itself accompanies
325the executable.
326
327 It may happen that this requirement contradicts the license
328restrictions of other proprietary libraries that do not normally
329accompany the operating system. Such a contradiction means you cannot
330use both them and the Library together in an executable that you
331distribute.
332
333 7. You may place library facilities that are a work based on the
334Library side-by-side in a single library together with other library
335facilities not covered by this License, and distribute such a combined
336library, provided that the separate distribution of the work based on
337the Library and of the other library facilities is otherwise
338permitted, and provided that you do these two things:
339
340 a) Accompany the combined library with a copy of the same work
341 based on the Library, uncombined with any other library
342 facilities. This must be distributed under the terms of the
343 Sections above.
344
345 b) Give prominent notice with the combined library of the fact
346 that part of it is a work based on the Library, and explaining
347 where to find the accompanying uncombined form of the same work.
348
349 8. You may not copy, modify, sublicense, link with, or distribute
350the Library except as expressly provided under this License. Any
351attempt otherwise to copy, modify, sublicense, link with, or
352distribute the Library is void, and will automatically terminate your
353rights under this License. However, parties who have received copies,
354or rights, from you under this License will not have their licenses
355terminated so long as such parties remain in full compliance.
356
357 9. You are not required to accept this License, since you have not
358signed it. However, nothing else grants you permission to modify or
359distribute the Library or its derivative works. These actions are
360prohibited by law if you do not accept this License. Therefore, by
361modifying or distributing the Library (or any work based on the
362Library), you indicate your acceptance of this License to do so, and
363all its terms and conditions for copying, distributing or modifying
364the Library or works based on it.
365
366 10. Each time you redistribute the Library (or any work based on the
367Library), the recipient automatically receives a license from the
368original licensor to copy, distribute, link with or modify the Library
369subject to these terms and conditions. You may not impose any further
370restrictions on the recipients' exercise of the rights granted herein.
371You are not responsible for enforcing compliance by third parties with
372this License.
373
374 11. If, as a consequence of a court judgment or allegation of patent
375infringement or for any other reason (not limited to patent issues),
376conditions are imposed on you (whether by court order, agreement or
377otherwise) that contradict the conditions of this License, they do not
378excuse you from the conditions of this License. If you cannot
379distribute so as to satisfy simultaneously your obligations under this
380License and any other pertinent obligations, then as a consequence you
381may not distribute the Library at all. For example, if a patent
382license would not permit royalty-free redistribution of the Library by
383all those who receive copies directly or indirectly through you, then
384the only way you could satisfy both it and this License would be to
385refrain entirely from distribution of the Library.
386
387If any portion of this section is held invalid or unenforceable under any
388particular circumstance, the balance of the section is intended to apply,
389and the section as a whole is intended to apply in other circumstances.
390
391It is not the purpose of this section to induce you to infringe any
392patents or other property right claims or to contest validity of any
393such claims; this section has the sole purpose of protecting the
394integrity of the free software distribution system which is
395implemented by public license practices. Many people have made
396generous contributions to the wide range of software distributed
397through that system in reliance on consistent application of that
398system; it is up to the author/donor to decide if he or she is willing
399to distribute software through any other system and a licensee cannot
400impose that choice.
401
402This section is intended to make thoroughly clear what is believed to
403be a consequence of the rest of this License.
404
405 12. If the distribution and/or use of the Library is restricted in
406certain countries either by patents or by copyrighted interfaces, the
407original copyright holder who places the Library under this License may add
408an explicit geographical distribution limitation excluding those countries,
409so that distribution is permitted only in or among countries not thus
410excluded. In such case, this License incorporates the limitation as if
411written in the body of this License.
412
413 13. The Free Software Foundation may publish revised and/or new
414versions of the Lesser General Public License from time to time.
415Such new versions will be similar in spirit to the present version,
416but may differ in detail to address new problems or concerns.
417
418Each version is given a distinguishing version number. If the Library
419specifies a version number of this License which applies to it and
420"any later version", you have the option of following the terms and
421conditions either of that version or of any later version published by
422the Free Software Foundation. If the Library does not specify a
423license version number, you may choose any version ever published by
424the Free Software Foundation.
425
426 14. If you wish to incorporate parts of the Library into other free
427programs whose distribution conditions are incompatible with these,
428write to the author to ask for permission. For software which is
429copyrighted by the Free Software Foundation, write to the Free
430Software Foundation; we sometimes make exceptions for this. Our
431decision will be guided by the two goals of preserving the free status
432of all derivatives of our free software and of promoting the sharing
433and reuse of software generally.
434
435 NO WARRANTY
436
437 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
438WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
439EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
440OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
441KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
442IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
443PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
444LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
445THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
446
447 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
448WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
449AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
450FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
451CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
452LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
453RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
454FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
455SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
456DAMAGES.
457
458 END OF TERMS AND CONDITIONS
459
460 How to Apply These Terms to Your New Libraries
461
462 If you develop a new library, and you want it to be of the greatest
463possible use to the public, we recommend making it free software that
464everyone can redistribute and change. You can do so by permitting
465redistribution under these terms (or, alternatively, under the terms of the
466ordinary General Public License).
467
468 To apply these terms, attach the following notices to the library. It is
469safest to attach them to the start of each source file to most effectively
470convey the exclusion of warranty; and each file should have at least the
471"copyright" line and a pointer to where the full notice is found.
472
473 <one line to give the library's name and a brief idea of what it does.>
474 Copyright (C) <year> <name of author>
475
476 This library is free software; you can redistribute it and/or
477 modify it under the terms of the GNU Lesser General Public
478 License as published by the Free Software Foundation; either
479 version 2.1 of the License, or (at your option) any later version.
480
481 This library is distributed in the hope that it will be useful,
482 but WITHOUT ANY WARRANTY; without even the implied warranty of
483 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
484 Lesser General Public License for more details.
485
486 You should have received a copy of the GNU Lesser General Public
487 License along with this library; if not, write to the Free Software
488 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
489
490Also add information on how to contact you by electronic and paper mail.
491
492You should also get your employer (if you work as a programmer) or your
493school, if any, to sign a "copyright disclaimer" for the library, if
494necessary. Here is a sample; alter the names:
495
496 Yoyodyne, Inc., hereby disclaims all copyright interest in the
497 library `Frob' (a library for tweaking knobs) written by James Random Hacker.
498
499 <signature of Ty Coon>, 1 April 1990
500 Ty Coon, President of Vice
501
502That's all there is to it!
diff --git a/tools/gator/daemon/libsensors/access.c b/tools/gator/daemon/libsensors/access.c
new file mode 100644
index 00000000000..8e227e2550d
--- /dev/null
+++ b/tools/gator/daemon/libsensors/access.c
@@ -0,0 +1,561 @@
1/*
2 access.c - Part of libsensors, a Linux library for reading sensor data.
3 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
4 Copyright (C) 2007-2009 Jean Delvare <khali@linux-fr.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301 USA.
20*/
21
22#include <stdlib.h>
23#include <string.h>
24#include <math.h>
25#include "access.h"
26#include "sensors.h"
27#include "data.h"
28#include "error.h"
29#include "sysfs.h"
30
31/* We watch the recursion depth for variables only, as an easy way to
32 detect cycles. */
33#define DEPTH_MAX 8
34
35static int sensors_eval_expr(const sensors_chip_features *chip_features,
36 const sensors_expr *expr,
37 double val, int depth, double *result);
38
39/* Compare two chips name descriptions, to see whether they could match.
40 Return 0 if it does not match, return 1 if it does match. */
41static int sensors_match_chip(const sensors_chip_name *chip1,
42 const sensors_chip_name *chip2)
43{
44 if ((chip1->prefix != SENSORS_CHIP_NAME_PREFIX_ANY) &&
45 (chip2->prefix != SENSORS_CHIP_NAME_PREFIX_ANY) &&
46 strcmp(chip1->prefix, chip2->prefix))
47 return 0;
48
49 if ((chip1->bus.type != SENSORS_BUS_TYPE_ANY) &&
50 (chip2->bus.type != SENSORS_BUS_TYPE_ANY) &&
51 (chip1->bus.type != chip2->bus.type))
52 return 0;
53
54 if ((chip1->bus.nr != SENSORS_BUS_NR_ANY) &&
55 (chip2->bus.nr != SENSORS_BUS_NR_ANY) &&
56 (chip1->bus.nr != chip2->bus.nr))
57 return 0;
58
59 if ((chip1->addr != chip2->addr) &&
60 (chip1->addr != SENSORS_CHIP_NAME_ADDR_ANY) &&
61 (chip2->addr != SENSORS_CHIP_NAME_ADDR_ANY))
62 return 0;
63
64 return 1;
65}
66
67/* Returns, one by one, a pointer to all sensor_chip structs of the
68 config file which match with the given chip name. Last should be
69 the value returned by the last call, or NULL if this is the first
70 call. Returns NULL if no more matches are found. Do not modify
71 the struct the return value points to!
72 Note that this visits the list of chips from last to first. Usually,
73 you want the match that was latest in the config file. */
74static sensors_chip *
75sensors_for_all_config_chips(const sensors_chip_name *name,
76 const sensors_chip *last)
77{
78 int nr, i;
79 sensors_chip_name_list chips;
80
81 for (nr = last ? last - sensors_config_chips - 1 :
82 sensors_config_chips_count - 1; nr >= 0; nr--) {
83
84 chips = sensors_config_chips[nr].chips;
85 for (i = 0; i < chips.fits_count; i++) {
86 if (sensors_match_chip(&chips.fits[i], name))
87 return sensors_config_chips + nr;
88 }
89 }
90 return NULL;
91}
92
93/* Look up a chip in the intern chip list, and return a pointer to it.
94 Do not modify the struct the return value points to! Returns NULL if
95 not found.*/
96static const sensors_chip_features *
97sensors_lookup_chip(const sensors_chip_name *name)
98{
99 int i;
100
101 for (i = 0; i < sensors_proc_chips_count; i++)
102 if (sensors_match_chip(&sensors_proc_chips[i].chip, name))
103 return &sensors_proc_chips[i];
104
105 return NULL;
106}
107
108/* Look up a subfeature of the given chip, and return a pointer to it.
109 Do not modify the struct the return value points to! Returns NULL if
110 not found.*/
111static const sensors_subfeature *
112sensors_lookup_subfeature_nr(const sensors_chip_features *chip,
113 int subfeat_nr)
114{
115 if (subfeat_nr < 0 ||
116 subfeat_nr >= chip->subfeature_count)
117 return NULL;
118 return chip->subfeature + subfeat_nr;
119}
120
121/* Look up a feature of the given chip, and return a pointer to it.
122 Do not modify the struct the return value points to! Returns NULL if
123 not found.*/
124static const sensors_feature *
125sensors_lookup_feature_nr(const sensors_chip_features *chip, int feat_nr)
126{
127 if (feat_nr < 0 ||
128 feat_nr >= chip->feature_count)
129 return NULL;
130 return chip->feature + feat_nr;
131}
132
133/* Look up a subfeature by name, and return a pointer to it.
134 Do not modify the struct the return value points to! Returns NULL if
135 not found.*/
136static const sensors_subfeature *
137sensors_lookup_subfeature_name(const sensors_chip_features *chip,
138 const char *name)
139{
140 int j;
141
142 for (j = 0; j < chip->subfeature_count; j++)
143 if (!strcmp(chip->subfeature[j].name, name))
144 return chip->subfeature + j;
145 return NULL;
146}
147
148/* Check whether the chip name is an 'absolute' name, which can only match
149 one chip, or whether it has wildcards. Returns 0 if it is absolute, 1
150 if there are wildcards. */
151int sensors_chip_name_has_wildcards(const sensors_chip_name *chip)
152{
153 if ((chip->prefix == SENSORS_CHIP_NAME_PREFIX_ANY) ||
154 (chip->bus.type == SENSORS_BUS_TYPE_ANY) ||
155 (chip->bus.nr == SENSORS_BUS_NR_ANY) ||
156 (chip->addr == SENSORS_CHIP_NAME_ADDR_ANY))
157 return 1;
158 else
159 return 0;
160}
161
162/* Look up the label for a given feature. Note that chip should not
163 contain wildcard values! The returned string is newly allocated (free it
164 yourself). On failure, NULL is returned.
165 If no label exists for this feature, its name is returned itself. */
166char *sensors_get_label(const sensors_chip_name *name,
167 const sensors_feature *feature)
168{
169 char *label;
170 const sensors_chip *chip;
171 char buf[PATH_MAX];
172 FILE *f;
173 int i;
174
175 if (sensors_chip_name_has_wildcards(name))
176 return NULL;
177
178 for (chip = NULL; (chip = sensors_for_all_config_chips(name, chip));)
179 for (i = 0; i < chip->labels_count; i++)
180 if (!strcmp(feature->name, chip->labels[i].name)) {
181 label = chip->labels[i].value;
182 goto sensors_get_label_exit;
183 }
184
185 /* No user specified label, check for a _label sysfs file */
186 snprintf(buf, PATH_MAX, "%s/%s_label", name->path, feature->name);
187
188 if ((f = fopen(buf, "r"))) {
189 i = fread(buf, 1, sizeof(buf), f);
190 fclose(f);
191 if (i > 0) {
192 /* i - 1 to strip the '\n' at the end */
193 buf[i - 1] = 0;
194 label = buf;
195 goto sensors_get_label_exit;
196 }
197 }
198
199 /* No label, return the feature name instead */
200 label = feature->name;
201
202sensors_get_label_exit:
203 label = strdup(label);
204 if (!label)
205 sensors_fatal_error(__func__, "Allocating label text");
206 return label;
207}
208
209/* Looks up whether a feature should be ignored. Returns
210 1 if it should be ignored, 0 if not. */
211static int sensors_get_ignored(const sensors_chip_name *name,
212 const sensors_feature *feature)
213{
214 const sensors_chip *chip;
215 int i;
216
217 for (chip = NULL; (chip = sensors_for_all_config_chips(name, chip));)
218 for (i = 0; i < chip->ignores_count; i++)
219 if (!strcmp(feature->name, chip->ignores[i].name))
220 return 1;
221 return 0;
222}
223
224/* Read the value of a subfeature of a certain chip. Note that chip should not
225 contain wildcard values! This function will return 0 on success, and <0
226 on failure. */
227static int __sensors_get_value(const sensors_chip_name *name, int subfeat_nr,
228 int depth, double *result)
229{
230 const sensors_chip_features *chip_features;
231 const sensors_subfeature *subfeature;
232 const sensors_expr *expr = NULL;
233 double val;
234 int res, i;
235
236 if (depth >= DEPTH_MAX)
237 return -SENSORS_ERR_RECURSION;
238 if (sensors_chip_name_has_wildcards(name))
239 return -SENSORS_ERR_WILDCARDS;
240 if (!(chip_features = sensors_lookup_chip(name)))
241 return -SENSORS_ERR_NO_ENTRY;
242 if (!(subfeature = sensors_lookup_subfeature_nr(chip_features,
243 subfeat_nr)))
244 return -SENSORS_ERR_NO_ENTRY;
245 if (!(subfeature->flags & SENSORS_MODE_R))
246 return -SENSORS_ERR_ACCESS_R;
247
248 /* Apply compute statement if it exists */
249 if (subfeature->flags & SENSORS_COMPUTE_MAPPING) {
250 const sensors_feature *feature;
251 const sensors_chip *chip;
252
253 feature = sensors_lookup_feature_nr(chip_features,
254 subfeature->mapping);
255
256 chip = NULL;
257 while (!expr &&
258 (chip = sensors_for_all_config_chips(name, chip)))
259 for (i = 0; i < chip->computes_count; i++) {
260 if (!strcmp(feature->name,
261 chip->computes[i].name)) {
262 expr = chip->computes[i].from_proc;
263 break;
264 }
265 }
266 }
267
268 res = sensors_read_sysfs_attr(name, subfeature, &val);
269 if (res)
270 return res;
271 if (!expr)
272 *result = val;
273 else if ((res = sensors_eval_expr(chip_features, expr, val, depth,
274 result)))
275 return res;
276 return 0;
277}
278
279int sensors_get_value(const sensors_chip_name *name, int subfeat_nr,
280 double *result)
281{
282 return __sensors_get_value(name, subfeat_nr, 0, result);
283}
284
285/* Set the value of a subfeature of a certain chip. Note that chip should not
286 contain wildcard values! This function will return 0 on success, and <0
287 on failure. */
288int sensors_set_value(const sensors_chip_name *name, int subfeat_nr,
289 double value)
290{
291 const sensors_chip_features *chip_features;
292 const sensors_subfeature *subfeature;
293 const sensors_expr *expr = NULL;
294 int i, res;
295 double to_write;
296
297 if (sensors_chip_name_has_wildcards(name))
298 return -SENSORS_ERR_WILDCARDS;
299 if (!(chip_features = sensors_lookup_chip(name)))
300 return -SENSORS_ERR_NO_ENTRY;
301 if (!(subfeature = sensors_lookup_subfeature_nr(chip_features,
302 subfeat_nr)))
303 return -SENSORS_ERR_NO_ENTRY;
304 if (!(subfeature->flags & SENSORS_MODE_W))
305 return -SENSORS_ERR_ACCESS_W;
306
307 /* Apply compute statement if it exists */
308 if (subfeature->flags & SENSORS_COMPUTE_MAPPING) {
309 const sensors_feature *feature;
310 const sensors_chip *chip;
311
312 feature = sensors_lookup_feature_nr(chip_features,
313 subfeature->mapping);
314
315 chip = NULL;
316 while (!expr &&
317 (chip = sensors_for_all_config_chips(name, chip)))
318 for (i = 0; i < chip->computes_count; i++) {
319 if (!strcmp(feature->name,
320 chip->computes[i].name)) {
321 expr = chip->computes[i].to_proc;
322 break;
323 }
324 }
325 }
326
327 to_write = value;
328 if (expr)
329 if ((res = sensors_eval_expr(chip_features, expr,
330 value, 0, &to_write)))
331 return res;
332 return sensors_write_sysfs_attr(name, subfeature, to_write);
333}
334
335const sensors_chip_name *sensors_get_detected_chips(const sensors_chip_name
336 *match, int *nr)
337{
338 const sensors_chip_name *res;
339
340 while (*nr < sensors_proc_chips_count) {
341 res = &sensors_proc_chips[(*nr)++].chip;
342 if (!match || sensors_match_chip(res, match))
343 return res;
344 }
345 return NULL;
346}
347
348const char *sensors_get_adapter_name(const sensors_bus_id *bus)
349{
350 int i;
351
352 /* bus types with a single instance */
353 switch (bus->type) {
354 case SENSORS_BUS_TYPE_ISA:
355 return "ISA adapter";
356 case SENSORS_BUS_TYPE_PCI:
357 return "PCI adapter";
358 /* SPI should not be here, but for now SPI adapters have no name
359 so we don't have any custom string to return. */
360 case SENSORS_BUS_TYPE_SPI:
361 return "SPI adapter";
362 case SENSORS_BUS_TYPE_VIRTUAL:
363 return "Virtual device";
364 case SENSORS_BUS_TYPE_ACPI:
365 return "ACPI interface";
366 /* HID should probably not be there either, but I don't know if
367 HID buses have a name nor where to find it. */
368 case SENSORS_BUS_TYPE_HID:
369 return "HID adapter";
370 }
371
372 /* bus types with several instances */
373 for (i = 0; i < sensors_proc_bus_count; i++)
374 if (sensors_proc_bus[i].bus.type == bus->type &&
375 sensors_proc_bus[i].bus.nr == bus->nr)
376 return sensors_proc_bus[i].adapter;
377 return NULL;
378}
379
380const sensors_feature *
381sensors_get_features(const sensors_chip_name *name, int *nr)
382{
383 const sensors_chip_features *chip;
384
385 if (!(chip = sensors_lookup_chip(name)))
386 return NULL; /* No such chip */
387
388 while (*nr < chip->feature_count
389 && sensors_get_ignored(name, &chip->feature[*nr]))
390 (*nr)++;
391 if (*nr >= chip->feature_count)
392 return NULL;
393 return &chip->feature[(*nr)++];
394}
395
396const sensors_subfeature *
397sensors_get_all_subfeatures(const sensors_chip_name *name,
398 const sensors_feature *feature, int *nr)
399{
400 const sensors_chip_features *chip;
401 const sensors_subfeature *subfeature;
402
403 if (!(chip = sensors_lookup_chip(name)))
404 return NULL; /* No such chip */
405
406 /* Seek directly to the first subfeature */
407 if (*nr < feature->first_subfeature)
408 *nr = feature->first_subfeature;
409
410 if (*nr >= chip->subfeature_count)
411 return NULL; /* end of list */
412 subfeature = &chip->subfeature[(*nr)++];
413 if (subfeature->mapping == feature->number)
414 return subfeature;
415 return NULL; /* end of subfeature list */
416}
417
418const sensors_subfeature *
419sensors_get_subfeature(const sensors_chip_name *name,
420 const sensors_feature *feature,
421 sensors_subfeature_type type)
422{
423 const sensors_chip_features *chip;
424 int i;
425
426 if (!(chip = sensors_lookup_chip(name)))
427 return NULL; /* No such chip */
428
429 for (i = feature->first_subfeature; i < chip->subfeature_count &&
430 chip->subfeature[i].mapping == feature->number; i++) {
431 if (chip->subfeature[i].type == type)
432 return &chip->subfeature[i];
433 }
434 return NULL; /* No such subfeature */
435}
436
437/* Evaluate an expression */
438int sensors_eval_expr(const sensors_chip_features *chip_features,
439 const sensors_expr *expr,
440 double val, int depth, double *result)
441{
442 double res1, res2;
443 int res;
444 const sensors_subfeature *subfeature;
445
446 if (expr->kind == sensors_kind_val) {
447 *result = expr->data.val;
448 return 0;
449 }
450 if (expr->kind == sensors_kind_source) {
451 *result = val;
452 return 0;
453 }
454 if (expr->kind == sensors_kind_var) {
455 if (!(subfeature = sensors_lookup_subfeature_name(chip_features,
456 expr->data.var)))
457 return -SENSORS_ERR_NO_ENTRY;
458 return __sensors_get_value(&chip_features->chip,
459 subfeature->number, depth + 1,
460 result);
461 }
462 if ((res = sensors_eval_expr(chip_features, expr->data.subexpr.sub1,
463 val, depth, &res1)))
464 return res;
465 if (expr->data.subexpr.sub2 &&
466 (res = sensors_eval_expr(chip_features, expr->data.subexpr.sub2,
467 val, depth, &res2)))
468 return res;
469 switch (expr->data.subexpr.op) {
470 case sensors_add:
471 *result = res1 + res2;
472 return 0;
473 case sensors_sub:
474 *result = res1 - res2;
475 return 0;
476 case sensors_multiply:
477 *result = res1 * res2;
478 return 0;
479 case sensors_divide:
480 if (res2 == 0.0)
481 return -SENSORS_ERR_DIV_ZERO;
482 *result = res1 / res2;
483 return 0;
484 case sensors_negate:
485 *result = -res1;
486 return 0;
487 case sensors_exp:
488 *result = exp(res1);
489 return 0;
490 case sensors_log:
491 if (res1 < 0.0)
492 return -SENSORS_ERR_DIV_ZERO;
493 *result = log(res1);
494 return 0;
495 }
496 return 0;
497}
498
499/* Execute all set statements for this particular chip. The chip may not
500 contain wildcards! This function will return 0 on success, and <0 on
501 failure. */
502static int sensors_do_this_chip_sets(const sensors_chip_name *name)
503{
504 const sensors_chip_features *chip_features;
505 sensors_chip *chip;
506 double value;
507 int i;
508 int err = 0, res;
509 const sensors_subfeature *subfeature;
510
511 chip_features = sensors_lookup_chip(name); /* Can't fail */
512
513 for (chip = NULL; (chip = sensors_for_all_config_chips(name, chip));)
514 for (i = 0; i < chip->sets_count; i++) {
515 subfeature = sensors_lookup_subfeature_name(chip_features,
516 chip->sets[i].name);
517 if (!subfeature) {
518 sensors_parse_error_wfn("Unknown feature name",
519 chip->sets[i].line.filename,
520 chip->sets[i].line.lineno);
521 err = -SENSORS_ERR_NO_ENTRY;
522 continue;
523 }
524
525 res = sensors_eval_expr(chip_features,
526 chip->sets[i].value, 0,
527 0, &value);
528 if (res) {
529 sensors_parse_error_wfn("Error parsing expression",
530 chip->sets[i].line.filename,
531 chip->sets[i].line.lineno);
532 err = res;
533 continue;
534 }
535 if ((res = sensors_set_value(name, subfeature->number,
536 value))) {
537 sensors_parse_error_wfn("Failed to set value",
538 chip->sets[i].line.filename,
539 chip->sets[i].line.lineno);
540 err = res;
541 continue;
542 }
543 }
544 return err;
545}
546
547/* Execute all set statements for this particular chip. The chip may contain
548 wildcards! This function will return 0 on success, and <0 on failure. */
549int sensors_do_chip_sets(const sensors_chip_name *name)
550{
551 int nr, this_res;
552 const sensors_chip_name *found_name;
553 int res = 0;
554
555 for (nr = 0; (found_name = sensors_get_detected_chips(name, &nr));) {
556 this_res = sensors_do_this_chip_sets(found_name);
557 if (this_res)
558 res = this_res;
559 }
560 return res;
561}
diff --git a/tools/gator/daemon/libsensors/access.h b/tools/gator/daemon/libsensors/access.h
new file mode 100644
index 00000000000..1d378434075
--- /dev/null
+++ b/tools/gator/daemon/libsensors/access.h
@@ -0,0 +1,33 @@
1/*
2 access.h - Part of libsensors, a Linux library for reading sensor data.
3 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
4 Copyright (C) 2007 Jean Delvare <khali@linux-fr.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301 USA.
20*/
21
22#ifndef LIB_SENSORS_ACCESS_H
23#define LIB_SENSORS_ACCESS_H
24
25#include "sensors.h"
26#include "data.h"
27
28/* Check whether the chip name is an 'absolute' name, which can only match
29 one chip, or whether it has wildcards. Returns 0 if it is absolute, 1
30 if there are wildcards. */
31int sensors_chip_name_has_wildcards(const sensors_chip_name *chip);
32
33#endif /* def LIB_SENSORS_ACCESS_H */
diff --git a/tools/gator/daemon/libsensors/conf-lex.c b/tools/gator/daemon/libsensors/conf-lex.c
new file mode 100644
index 00000000000..a54664b3d77
--- /dev/null
+++ b/tools/gator/daemon/libsensors/conf-lex.c
@@ -0,0 +1,2881 @@
1
2#line 3 "<stdout>"
3
4#define YY_INT_ALIGNED short int
5
6/* A lexical scanner generated by flex */
7
8#define yy_create_buffer sensors_yy_create_buffer
9#define yy_delete_buffer sensors_yy_delete_buffer
10#define yy_flex_debug sensors_yy_flex_debug
11#define yy_init_buffer sensors_yy_init_buffer
12#define yy_flush_buffer sensors_yy_flush_buffer
13#define yy_load_buffer_state sensors_yy_load_buffer_state
14#define yy_switch_to_buffer sensors_yy_switch_to_buffer
15#define yyin sensors_yyin
16#define yyleng sensors_yyleng
17#define yylex sensors_yylex
18#define yylineno sensors_yylineno
19#define yyout sensors_yyout
20#define yyrestart sensors_yyrestart
21#define yytext sensors_yytext
22#define yywrap sensors_yywrap
23#define yyalloc sensors_yyalloc
24#define yyrealloc sensors_yyrealloc
25#define yyfree sensors_yyfree
26
27#define FLEX_SCANNER
28#define YY_FLEX_MAJOR_VERSION 2
29#define YY_FLEX_MINOR_VERSION 5
30#define YY_FLEX_SUBMINOR_VERSION 35
31#if YY_FLEX_SUBMINOR_VERSION > 0
32#define FLEX_BETA
33#endif
34
35/* First, we deal with platform-specific or compiler-specific issues. */
36
37/* begin standard C headers. */
38#include <stdio.h>
39#include <string.h>
40#include <errno.h>
41#include <stdlib.h>
42
43/* end standard C headers. */
44
45/* flex integer type definitions */
46
47#ifndef FLEXINT_H
48#define FLEXINT_H
49
50/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
51
52#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
53
54/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
55 * if you want the limit (max/min) macros for int types.
56 */
57#ifndef __STDC_LIMIT_MACROS
58#define __STDC_LIMIT_MACROS 1
59#endif
60
61#include <inttypes.h>
62typedef int8_t flex_int8_t;
63typedef uint8_t flex_uint8_t;
64typedef int16_t flex_int16_t;
65typedef uint16_t flex_uint16_t;
66typedef int32_t flex_int32_t;
67typedef uint32_t flex_uint32_t;
68#else
69typedef signed char flex_int8_t;
70typedef short int flex_int16_t;
71typedef int flex_int32_t;
72typedef unsigned char flex_uint8_t;
73typedef unsigned short int flex_uint16_t;
74typedef unsigned int flex_uint32_t;
75
76/* Limits of integral types. */
77#ifndef INT8_MIN
78#define INT8_MIN (-128)
79#endif
80#ifndef INT16_MIN
81#define INT16_MIN (-32767-1)
82#endif
83#ifndef INT32_MIN
84#define INT32_MIN (-2147483647-1)
85#endif
86#ifndef INT8_MAX
87#define INT8_MAX (127)
88#endif
89#ifndef INT16_MAX
90#define INT16_MAX (32767)
91#endif
92#ifndef INT32_MAX
93#define INT32_MAX (2147483647)
94#endif
95#ifndef UINT8_MAX
96#define UINT8_MAX (255U)
97#endif
98#ifndef UINT16_MAX
99#define UINT16_MAX (65535U)
100#endif
101#ifndef UINT32_MAX
102#define UINT32_MAX (4294967295U)
103#endif
104
105#endif /* ! C99 */
106
107#endif /* ! FLEXINT_H */
108
109#ifdef __cplusplus
110
111/* The "const" storage-class-modifier is valid. */
112#define YY_USE_CONST
113
114#else /* ! __cplusplus */
115
116/* C99 requires __STDC__ to be defined as 1. */
117#if defined (__STDC__)
118
119#define YY_USE_CONST
120
121#endif /* defined (__STDC__) */
122#endif /* ! __cplusplus */
123
124#ifdef YY_USE_CONST
125#define yyconst const
126#else
127#define yyconst
128#endif
129
130/* Returned upon end-of-file. */
131#define YY_NULL 0
132
133/* Promotes a possibly negative, possibly signed char to an unsigned
134 * integer for use as an array index. If the signed char is negative,
135 * we want to instead treat it as an 8-bit unsigned char, hence the
136 * double cast.
137 */
138#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
139
140/* Enter a start condition. This macro really ought to take a parameter,
141 * but we do it the disgusting crufty way forced on us by the ()-less
142 * definition of BEGIN.
143 */
144#define BEGIN (yy_start) = 1 + 2 *
145
146/* Translate the current start state into a value that can be later handed
147 * to BEGIN to return to the state. The YYSTATE alias is for lex
148 * compatibility.
149 */
150#define YY_START (((yy_start) - 1) / 2)
151#define YYSTATE YY_START
152
153/* Action number for EOF rule of a given start state. */
154#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
155
156/* Special action meaning "start processing a new file". */
157#define YY_NEW_FILE sensors_yyrestart(sensors_yyin )
158
159#define YY_END_OF_BUFFER_CHAR 0
160
161/* Size of default input buffer. */
162#ifndef YY_BUF_SIZE
163#ifdef __ia64__
164/* On IA-64, the buffer size is 16k, not 8k.
165 * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
166 * Ditto for the __ia64__ case accordingly.
167 */
168#define YY_BUF_SIZE 32768
169#else
170#define YY_BUF_SIZE 16384
171#endif /* __ia64__ */
172#endif
173
174/* The state buf must be large enough to hold one state per character in the main buffer.
175 */
176#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
177
178#ifndef YY_TYPEDEF_YY_BUFFER_STATE
179#define YY_TYPEDEF_YY_BUFFER_STATE
180typedef struct yy_buffer_state *YY_BUFFER_STATE;
181#endif
182
183extern int sensors_yyleng;
184
185extern FILE *sensors_yyin, *sensors_yyout;
186
187#define EOB_ACT_CONTINUE_SCAN 0
188#define EOB_ACT_END_OF_FILE 1
189#define EOB_ACT_LAST_MATCH 2
190
191 #define YY_LESS_LINENO(n)
192
193/* Return all but the first "n" matched characters back to the input stream. */
194#define yyless(n) \
195 do \
196 { \
197 /* Undo effects of setting up sensors_yytext. */ \
198 int yyless_macro_arg = (n); \
199 YY_LESS_LINENO(yyless_macro_arg);\
200 *yy_cp = (yy_hold_char); \
201 YY_RESTORE_YY_MORE_OFFSET \
202 (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
203 YY_DO_BEFORE_ACTION; /* set up sensors_yytext again */ \
204 } \
205 while ( 0 )
206
207#define unput(c) yyunput( c, (yytext_ptr) )
208
209#ifndef YY_TYPEDEF_YY_SIZE_T
210#define YY_TYPEDEF_YY_SIZE_T
211typedef size_t yy_size_t;
212#endif
213
214#ifndef YY_STRUCT_YY_BUFFER_STATE
215#define YY_STRUCT_YY_BUFFER_STATE
216struct yy_buffer_state
217 {
218 FILE *yy_input_file;
219
220 char *yy_ch_buf; /* input buffer */
221 char *yy_buf_pos; /* current position in input buffer */
222
223 /* Size of input buffer in bytes, not including room for EOB
224 * characters.
225 */
226 yy_size_t yy_buf_size;
227
228 /* Number of characters read into yy_ch_buf, not including EOB
229 * characters.
230 */
231 int yy_n_chars;
232
233 /* Whether we "own" the buffer - i.e., we know we created it,
234 * and can realloc() it to grow it, and should free() it to
235 * delete it.
236 */
237 int yy_is_our_buffer;
238
239 /* Whether this is an "interactive" input source; if so, and
240 * if we're using stdio for input, then we want to use getc()
241 * instead of fread(), to make sure we stop fetching input after
242 * each newline.
243 */
244 int yy_is_interactive;
245
246 /* Whether we're considered to be at the beginning of a line.
247 * If so, '^' rules will be active on the next match, otherwise
248 * not.
249 */
250 int yy_at_bol;
251
252 int yy_bs_lineno; /**< The line count. */
253 int yy_bs_column; /**< The column count. */
254
255 /* Whether to try to fill the input buffer when we reach the
256 * end of it.
257 */
258 int yy_fill_buffer;
259
260 int yy_buffer_status;
261
262#define YY_BUFFER_NEW 0
263#define YY_BUFFER_NORMAL 1
264 /* When an EOF's been seen but there's still some text to process
265 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
266 * shouldn't try reading from the input source any more. We might
267 * still have a bunch of tokens to match, though, because of
268 * possible backing-up.
269 *
270 * When we actually see the EOF, we change the status to "new"
271 * (via sensors_yyrestart()), so that the user can continue scanning by
272 * just pointing sensors_yyin at a new input file.
273 */
274#define YY_BUFFER_EOF_PENDING 2
275
276 };
277#endif /* !YY_STRUCT_YY_BUFFER_STATE */
278
279/* Stack of input buffers. */
280static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
281static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
282static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
283
284/* We provide macros for accessing buffer states in case in the
285 * future we want to put the buffer states in a more general
286 * "scanner state".
287 *
288 * Returns the top of the stack, or NULL.
289 */
290#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
291 ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
292 : NULL)
293
294/* Same as previous macro, but useful when we know that the buffer stack is not
295 * NULL or when we need an lvalue. For internal use only.
296 */
297#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
298
299/* yy_hold_char holds the character lost when sensors_yytext is formed. */
300static char yy_hold_char;
301static int yy_n_chars; /* number of characters read into yy_ch_buf */
302int sensors_yyleng;
303
304/* Points to current character in buffer. */
305static char *yy_c_buf_p = (char *) 0;
306static int yy_init = 0; /* whether we need to initialize */
307static int yy_start = 0; /* start state number */
308
309/* Flag which is used to allow sensors_yywrap()'s to do buffer switches
310 * instead of setting up a fresh sensors_yyin. A bit of a hack ...
311 */
312static int yy_did_buffer_switch_on_eof;
313
314void sensors_yyrestart (FILE *input_file );
315void sensors_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer );
316YY_BUFFER_STATE sensors_yy_create_buffer (FILE *file,int size );
317void sensors_yy_delete_buffer (YY_BUFFER_STATE b );
318void sensors_yy_flush_buffer (YY_BUFFER_STATE b );
319void sensors_yypush_buffer_state (YY_BUFFER_STATE new_buffer );
320void sensors_yypop_buffer_state (void );
321
322static void sensors_yyensure_buffer_stack (void );
323static void sensors_yy_load_buffer_state (void );
324static void sensors_yy_init_buffer (YY_BUFFER_STATE b,FILE *file );
325
326#define YY_FLUSH_BUFFER sensors_yy_flush_buffer(YY_CURRENT_BUFFER )
327
328YY_BUFFER_STATE sensors_yy_scan_buffer (char *base,yy_size_t size );
329YY_BUFFER_STATE sensors_yy_scan_string (yyconst char *yy_str );
330YY_BUFFER_STATE sensors_yy_scan_bytes (yyconst char *bytes,int len );
331
332void *sensors_yyalloc (yy_size_t );
333void *sensors_yyrealloc (void *,yy_size_t );
334void sensors_yyfree (void * );
335
336#define yy_new_buffer sensors_yy_create_buffer
337
338#define yy_set_interactive(is_interactive) \
339 { \
340 if ( ! YY_CURRENT_BUFFER ){ \
341 sensors_yyensure_buffer_stack (); \
342 YY_CURRENT_BUFFER_LVALUE = \
343 sensors_yy_create_buffer(sensors_yyin,YY_BUF_SIZE ); \
344 } \
345 YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
346 }
347
348#define yy_set_bol(at_bol) \
349 { \
350 if ( ! YY_CURRENT_BUFFER ){\
351 sensors_yyensure_buffer_stack (); \
352 YY_CURRENT_BUFFER_LVALUE = \
353 sensors_yy_create_buffer(sensors_yyin,YY_BUF_SIZE ); \
354 } \
355 YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
356 }
357
358#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
359
360/* Begin user sect3 */
361
362#define sensors_yywrap(n) 1
363#define YY_SKIP_YYWRAP
364
365typedef unsigned char YY_CHAR;
366
367FILE *sensors_yyin = (FILE *) 0, *sensors_yyout = (FILE *) 0;
368
369typedef int yy_state_type;
370
371extern int sensors_yylineno;
372
373int sensors_yylineno = 1;
374
375extern char *sensors_yytext;
376#define yytext_ptr sensors_yytext
377static yyconst flex_int16_t yy_nxt[][39] =
378 {
379 {
380 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
381 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
382 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
383 0, 0, 0, 0, 0, 0, 0, 0, 0
384 },
385
386 {
387 9, 10, 11, 12, 10, 13, 10, 10, 10, 10,
388 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
389 14, 15, 16, 14, 14, 14, 14, 14, 17, 18,
390 14, 14, 14, 14, 14, 19, 14, 14, 14
391 },
392
393 {
394 9, 10, 11, 12, 10, 13, 10, 10, 10, 10,
395 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
396
397 14, 15, 16, 14, 14, 14, 14, 14, 17, 18,
398 14, 14, 14, 14, 14, 19, 14, 14, 14
399 },
400
401 {
402 9, 20, 21, 22, 23, 24, 25, 26, 27, 28,
403 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
404 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
405 35, 35, 35, 35, 35, 35, 35, 35, 35
406 },
407
408 {
409 9, 20, 21, 22, 23, 24, 25, 26, 27, 28,
410 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
411 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
412 35, 35, 35, 35, 35, 35, 35, 35, 35
413
414 },
415
416 {
417 9, 39, 39, 40, 41, 39, 39, 39, 39, 39,
418 39, 39, 39, 39, 39, 39, 39, 42, 39, 39,
419 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
420 39, 39, 39, 39, 39, 39, 39, 39, 39
421 },
422
423 {
424 9, 39, 39, 40, 41, 39, 39, 39, 39, 39,
425 39, 39, 39, 39, 39, 39, 39, 42, 39, 39,
426 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
427 39, 39, 39, 39, 39, 39, 39, 39, 39
428 },
429
430 {
431 9, 43, 43, 44, 43, 43, 43, 43, 43, 43,
432 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
433
434 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
435 43, 43, 43, 43, 43, 43, 43, 43, 43
436 },
437
438 {
439 9, 43, 43, 44, 43, 43, 43, 43, 43, 43,
440 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
441 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
442 43, 43, 43, 43, 43, 43, 43, 43, 43
443 },
444
445 {
446 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
447 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
448 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
449 -9, -9, -9, -9, -9, -9, -9, -9, -9
450
451 },
452
453 {
454 9, -10, -10, -10, -10, -10, -10, -10, -10, -10,
455 -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
456 -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
457 -10, -10, -10, -10, -10, -10, -10, -10, -10
458 },
459
460 {
461 9, -11, 45, 46, -11, -11, -11, -11, -11, -11,
462 -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
463 -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
464 -11, -11, -11, -11, -11, -11, -11, -11, -11
465 },
466
467 {
468 9, -12, -12, -12, -12, -12, -12, -12, -12, -12,
469 -12, -12, -12, -12, -12, -12, -12, -12, -12, -12,
470
471 -12, -12, -12, -12, -12, -12, -12, -12, -12, -12,
472 -12, -12, -12, -12, -12, -12, -12, -12, -12
473 },
474
475 {
476 9, 47, 47, 48, 47, 47, 47, 47, 47, 47,
477 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
478 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
479 47, 47, 47, 47, 47, 47, 47, 47, 47
480 },
481
482 {
483 9, -14, -14, -14, -14, -14, -14, -14, -14, -14,
484 -14, -14, -14, -14, -14, -14, -14, -14, -14, -14,
485 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
486 49, 49, 49, 49, 49, 49, 49, 49, 49
487
488 },
489
490 {
491 9, -15, -15, -15, -15, -15, -15, -15, -15, -15,
492 -15, -15, -15, -15, -15, -15, -15, -15, -15, -15,
493 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
494 49, 49, 49, 49, 49, 49, 49, 50, 49
495 },
496
497 {
498 9, -16, -16, -16, -16, -16, -16, -16, -16, -16,
499 -16, -16, -16, -16, -16, -16, -16, -16, -16, -16,
500 49, 49, 49, 49, 49, 49, 49, 51, 49, 49,
501 49, 49, 52, 49, 49, 49, 49, 49, 49
502 },
503
504 {
505 9, -17, -17, -17, -17, -17, -17, -17, -17, -17,
506 -17, -17, -17, -17, -17, -17, -17, -17, -17, -17,
507
508 49, 49, 49, 49, 49, 49, 53, 49, 49, 49,
509 49, 49, 49, 49, 49, 49, 49, 49, 49
510 },
511
512 {
513 9, -18, -18, -18, -18, -18, -18, -18, -18, -18,
514 -18, -18, -18, -18, -18, -18, -18, -18, -18, -18,
515 54, 49, 49, 49, 49, 49, 49, 49, 49, 49,
516 49, 49, 49, 49, 49, 49, 49, 49, 49
517 },
518
519 {
520 9, -19, -19, -19, -19, -19, -19, -19, -19, -19,
521 -19, -19, -19, -19, -19, -19, -19, -19, -19, -19,
522 49, 49, 49, 49, 55, 49, 49, 49, 49, 49,
523 49, 49, 49, 49, 49, 49, 49, 49, 49
524
525 },
526
527 {
528 9, -20, -20, -20, -20, -20, -20, -20, -20, -20,
529 -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,
530 -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,
531 -20, -20, -20, -20, -20, -20, -20, -20, -20
532 },
533
534 {
535 9, -21, 56, -21, -21, -21, -21, -21, -21, -21,
536 -21, -21, -21, -21, -21, -21, -21, -21, -21, -21,
537 -21, -21, -21, -21, -21, -21, -21, -21, -21, -21,
538 -21, -21, -21, -21, -21, -21, -21, -21, -21
539 },
540
541 {
542 9, -22, -22, -22, -22, -22, -22, -22, -22, -22,
543 -22, -22, -22, -22, -22, -22, -22, -22, -22, -22,
544
545 -22, -22, -22, -22, -22, -22, -22, -22, -22, -22,
546 -22, -22, -22, -22, -22, -22, -22, -22, -22
547 },
548
549 {
550 9, -23, -23, -23, -23, -23, -23, -23, -23, -23,
551 -23, -23, -23, -23, -23, -23, -23, -23, -23, -23,
552 -23, -23, -23, -23, -23, -23, -23, -23, -23, -23,
553 -23, -23, -23, -23, -23, -23, -23, -23, -23
554 },
555
556 {
557 9, 57, 57, 58, 57, 57, 57, 57, 57, 57,
558 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
559 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
560 57, 57, 57, 57, 57, 57, 57, 57, 57
561
562 },
563
564 {
565 9, -25, -25, -25, -25, -25, -25, -25, -25, -25,
566 -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
567 -25, -25, -25, -25, -25, -25, -25, -25, -25, -25,
568 -25, -25, -25, -25, -25, -25, -25, -25, -25
569 },
570
571 {
572 9, -26, -26, -26, -26, -26, -26, -26, -26, -26,
573 -26, -26, -26, -26, -26, -26, -26, -26, -26, -26,
574 -26, -26, -26, -26, -26, -26, -26, -26, -26, -26,
575 -26, -26, -26, -26, -26, -26, -26, -26, -26
576 },
577
578 {
579 9, -27, -27, -27, -27, -27, -27, -27, -27, -27,
580 -27, -27, -27, -27, -27, -27, -27, -27, -27, -27,
581
582 -27, -27, -27, -27, -27, -27, -27, -27, -27, -27,
583 -27, -27, -27, -27, -27, -27, -27, -27, -27
584 },
585
586 {
587 9, -28, -28, -28, -28, -28, -28, -28, -28, -28,
588 -28, -28, -28, -28, -28, -28, -28, -28, -28, -28,
589 -28, -28, -28, -28, -28, -28, -28, -28, -28, -28,
590 -28, -28, -28, -28, -28, -28, -28, -28, -28
591 },
592
593 {
594 9, -29, -29, -29, -29, -29, -29, -29, -29, -29,
595 -29, -29, -29, -29, -29, -29, -29, -29, -29, -29,
596 -29, -29, -29, -29, -29, -29, -29, -29, -29, -29,
597 -29, -29, -29, -29, -29, -29, -29, -29, -29
598
599 },
600
601 {
602 9, -30, -30, -30, -30, -30, -30, -30, -30, -30,
603 -30, -30, -30, -30, -30, -30, -30, -30, -30, -30,
604 -30, -30, -30, -30, -30, -30, -30, -30, -30, -30,
605 -30, -30, -30, -30, -30, -30, -30, -30, -30
606 },
607
608 {
609 9, -31, -31, -31, -31, -31, -31, -31, -31, -31,
610 -31, -31, -31, -31, 59, -31, -31, -31, -31, -31,
611 -31, -31, -31, -31, -31, -31, -31, -31, -31, -31,
612 -31, -31, -31, -31, -31, -31, -31, -31, -31
613 },
614
615 {
616 9, -32, -32, -32, -32, -32, -32, -32, -32, -32,
617 -32, -32, -32, -32, -32, -32, -32, -32, -32, -32,
618
619 -32, -32, -32, -32, -32, -32, -32, -32, -32, -32,
620 -32, -32, -32, -32, -32, -32, -32, -32, -32
621 },
622
623 {
624 9, -33, -33, -33, -33, -33, -33, -33, -33, -33,
625 -33, -33, 60, -33, 61, -33, 62, -33, -33, -33,
626 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
627 62, 62, 62, 62, 62, 62, 62, 62, 62
628 },
629
630 {
631 9, -34, -34, -34, -34, -34, -34, -34, -34, -34,
632 -34, -34, -34, -34, -34, -34, -34, -34, -34, -34,
633 -34, -34, -34, -34, -34, -34, -34, -34, -34, -34,
634 -34, -34, -34, -34, -34, -34, -34, -34, -34
635
636 },
637
638 {
639 9, -35, -35, -35, -35, -35, -35, -35, -35, -35,
640 -35, -35, -35, -35, 62, -35, 62, -35, -35, -35,
641 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
642 62, 62, 62, 62, 62, 62, 62, 62, 62
643 },
644
645 {
646 9, -36, 63, 64, -36, -36, -36, -36, -36, -36,
647 -36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
648 -36, -36, -36, -36, -36, -36, -36, -36, -36, -36,
649 -36, -36, -36, -36, -36, -36, -36, -36, -36
650 },
651
652 {
653 9, -37, -37, -37, -37, -37, -37, -37, -37, -37,
654 -37, -37, -37, -37, -37, -37, -37, -37, -37, -37,
655
656 -37, -37, -37, -37, -37, -37, -37, -37, -37, -37,
657 -37, -37, -37, -37, -37, -37, -37, -37, -37
658 },
659
660 {
661 9, -38, -38, -38, -38, -38, -38, -38, -38, -38,
662 -38, -38, -38, -38, -38, -38, -38, -38, -38, -38,
663 -38, -38, -38, -38, -38, -38, -38, -38, -38, -38,
664 -38, -38, -38, -38, -38, -38, -38, -38, -38
665 },
666
667 {
668 9, 65, 65, -39, -39, 65, 65, 65, 65, 65,
669 65, 65, 65, 65, 65, 65, 65, -39, 65, 65,
670 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
671 65, 65, 65, 65, 65, 65, 65, 65, 65
672
673 },
674
675 {
676 9, -40, -40, -40, -40, -40, -40, -40, -40, -40,
677 -40, -40, -40, -40, -40, -40, -40, -40, -40, -40,
678 -40, -40, -40, -40, -40, -40, -40, -40, -40, -40,
679 -40, -40, -40, -40, -40, -40, -40, -40, -40
680 },
681
682 {
683 9, -41, -41, -41, 66, -41, -41, -41, -41, -41,
684 -41, -41, -41, -41, -41, -41, -41, -41, -41, -41,
685 -41, -41, -41, -41, -41, -41, -41, -41, -41, -41,
686 -41, -41, -41, -41, -41, -41, -41, -41, -41
687 },
688
689 {
690 9, 67, 67, 68, 67, 67, 67, 67, 67, 67,
691 67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
692
693 69, 70, 67, 67, 67, 71, 67, 67, 67, 67,
694 67, 72, 67, 67, 73, 67, 74, 67, 75
695 },
696
697 {
698 9, 76, 76, -43, 76, 76, 76, 76, 76, 76,
699 76, 76, 76, 76, 76, 76, 76, 76, 76, 76,
700 76, 76, 76, 76, 76, 76, 76, 76, 76, 76,
701 76, 76, 76, 76, 76, 76, 76, 76, 76
702 },
703
704 {
705 9, -44, -44, -44, -44, -44, -44, -44, -44, -44,
706 -44, -44, -44, -44, -44, -44, -44, -44, -44, -44,
707 -44, -44, -44, -44, -44, -44, -44, -44, -44, -44,
708 -44, -44, -44, -44, -44, -44, -44, -44, -44
709
710 },
711
712 {
713 9, -45, 45, 46, -45, -45, -45, -45, -45, -45,
714 -45, -45, -45, -45, -45, -45, -45, -45, -45, -45,
715 -45, -45, -45, -45, -45, -45, -45, -45, -45, -45,
716 -45, -45, -45, -45, -45, -45, -45, -45, -45
717 },
718
719 {
720 9, -46, -46, -46, -46, -46, -46, -46, -46, -46,
721 -46, -46, -46, -46, -46, -46, -46, -46, -46, -46,
722 -46, -46, -46, -46, -46, -46, -46, -46, -46, -46,
723 -46, -46, -46, -46, -46, -46, -46, -46, -46
724 },
725
726 {
727 9, 47, 47, 48, 47, 47, 47, 47, 47, 47,
728 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
729
730 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
731 47, 47, 47, 47, 47, 47, 47, 47, 47
732 },
733
734 {
735 9, -48, -48, -48, -48, -48, -48, -48, -48, -48,
736 -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
737 -48, -48, -48, -48, -48, -48, -48, -48, -48, -48,
738 -48, -48, -48, -48, -48, -48, -48, -48, -48
739 },
740
741 {
742 9, -49, -49, -49, -49, -49, -49, -49, -49, -49,
743 -49, -49, -49, -49, -49, -49, -49, -49, -49, -49,
744 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
745 49, 49, 49, 49, 49, 49, 49, 49, 49
746
747 },
748
749 {
750 9, -50, -50, -50, -50, -50, -50, -50, -50, -50,
751 -50, -50, -50, -50, -50, -50, -50, -50, -50, -50,
752 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
753 49, 49, 49, 49, 49, 77, 49, 49, 49
754 },
755
756 {
757 9, -51, -51, -51, -51, -51, -51, -51, -51, -51,
758 -51, -51, -51, -51, -51, -51, -51, -51, -51, -51,
759 49, 49, 49, 49, 49, 49, 49, 49, 78, 49,
760 49, 49, 49, 49, 49, 49, 49, 49, 49
761 },
762
763 {
764 9, -52, -52, -52, -52, -52, -52, -52, -52, -52,
765 -52, -52, -52, -52, -52, -52, -52, -52, -52, -52,
766
767 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
768 79, 49, 49, 49, 49, 49, 49, 49, 49
769 },
770
771 {
772 9, -53, -53, -53, -53, -53, -53, -53, -53, -53,
773 -53, -53, -53, -53, -53, -53, -53, -53, -53, -53,
774 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
775 49, 80, 49, 49, 49, 49, 49, 49, 49
776 },
777
778 {
779 9, -54, -54, -54, -54, -54, -54, -54, -54, -54,
780 -54, -54, -54, -54, -54, -54, -54, -54, -54, -54,
781 49, 81, 49, 49, 49, 49, 49, 49, 49, 49,
782 49, 49, 49, 49, 49, 49, 49, 49, 49
783
784 },
785
786 {
787 9, -55, -55, -55, -55, -55, -55, -55, -55, -55,
788 -55, -55, -55, -55, -55, -55, -55, -55, -55, -55,
789 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
790 49, 49, 49, 49, 49, 49, 82, 49, 49
791 },
792
793 {
794 9, -56, 56, -56, -56, -56, -56, -56, -56, -56,
795 -56, -56, -56, -56, -56, -56, -56, -56, -56, -56,
796 -56, -56, -56, -56, -56, -56, -56, -56, -56, -56,
797 -56, -56, -56, -56, -56, -56, -56, -56, -56
798 },
799
800 {
801 9, 57, 57, 58, 57, 57, 57, 57, 57, 57,
802 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
803
804 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
805 57, 57, 57, 57, 57, 57, 57, 57, 57
806 },
807
808 {
809 9, -58, -58, -58, -58, -58, -58, -58, -58, -58,
810 -58, -58, -58, -58, -58, -58, -58, -58, -58, -58,
811 -58, -58, -58, -58, -58, -58, -58, -58, -58, -58,
812 -58, -58, -58, -58, -58, -58, -58, -58, -58
813 },
814
815 {
816 9, -59, -59, -59, -59, -59, -59, -59, -59, -59,
817 -59, -59, -59, -59, 59, -59, -59, -59, -59, -59,
818 -59, -59, -59, -59, -59, -59, -59, -59, -59, -59,
819 -59, -59, -59, -59, -59, -59, -59, -59, -59
820
821 },
822
823 {
824 9, -60, -60, -60, -60, -60, -60, -60, -60, -60,
825 -60, -60, -60, -60, 59, -60, -60, -60, -60, -60,
826 -60, -60, -60, -60, -60, -60, -60, -60, -60, -60,
827 -60, -60, -60, -60, -60, -60, -60, -60, -60
828 },
829
830 {
831 9, -61, -61, -61, -61, -61, -61, -61, -61, -61,
832 -61, -61, 60, -61, 61, -61, 62, -61, -61, -61,
833 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
834 62, 62, 62, 62, 62, 62, 62, 62, 62
835 },
836
837 {
838 9, -62, -62, -62, -62, -62, -62, -62, -62, -62,
839 -62, -62, -62, -62, 62, -62, 62, -62, -62, -62,
840
841 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
842 62, 62, 62, 62, 62, 62, 62, 62, 62
843 },
844
845 {
846 9, -63, 63, 64, -63, -63, -63, -63, -63, -63,
847 -63, -63, -63, -63, -63, -63, -63, -63, -63, -63,
848 -63, -63, -63, -63, -63, -63, -63, -63, -63, -63,
849 -63, -63, -63, -63, -63, -63, -63, -63, -63
850 },
851
852 {
853 9, -64, -64, -64, -64, -64, -64, -64, -64, -64,
854 -64, -64, -64, -64, -64, -64, -64, -64, -64, -64,
855 -64, -64, -64, -64, -64, -64, -64, -64, -64, -64,
856 -64, -64, -64, -64, -64, -64, -64, -64, -64
857
858 },
859
860 {
861 9, 65, 65, -65, -65, 65, 65, 65, 65, 65,
862 65, 65, 65, 65, 65, 65, 65, -65, 65, 65,
863 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
864 65, 65, 65, 65, 65, 65, 65, 65, 65
865 },
866
867 {
868 9, -66, -66, -66, -66, -66, -66, -66, -66, -66,
869 -66, -66, -66, -66, -66, -66, -66, -66, -66, -66,
870 -66, -66, -66, -66, -66, -66, -66, -66, -66, -66,
871 -66, -66, -66, -66, -66, -66, -66, -66, -66
872 },
873
874 {
875 9, -67, -67, -67, -67, -67, -67, -67, -67, -67,
876 -67, -67, -67, -67, -67, -67, -67, -67, -67, -67,
877
878 -67, -67, -67, -67, -67, -67, -67, -67, -67, -67,
879 -67, -67, -67, -67, -67, -67, -67, -67, -67
880 },
881
882 {
883 9, -68, -68, -68, -68, -68, -68, -68, -68, -68,
884 -68, -68, -68, -68, -68, -68, -68, -68, -68, -68,
885 -68, -68, -68, -68, -68, -68, -68, -68, -68, -68,
886 -68, -68, -68, -68, -68, -68, -68, -68, -68
887 },
888
889 {
890 9, -69, -69, -69, -69, -69, -69, -69, -69, -69,
891 -69, -69, -69, -69, -69, -69, -69, -69, -69, -69,
892 -69, -69, -69, -69, -69, -69, -69, -69, -69, -69,
893 -69, -69, -69, -69, -69, -69, -69, -69, -69
894
895 },
896
897 {
898 9, -70, -70, -70, -70, -70, -70, -70, -70, -70,
899 -70, -70, -70, -70, -70, -70, -70, -70, -70, -70,
900 -70, -70, -70, -70, -70, -70, -70, -70, -70, -70,
901 -70, -70, -70, -70, -70, -70, -70, -70, -70
902 },
903
904 {
905 9, -71, -71, -71, -71, -71, -71, -71, -71, -71,
906 -71, -71, -71, -71, -71, -71, -71, -71, -71, -71,
907 -71, -71, -71, -71, -71, -71, -71, -71, -71, -71,
908 -71, -71, -71, -71, -71, -71, -71, -71, -71
909 },
910
911 {
912 9, -72, -72, -72, -72, -72, -72, -72, -72, -72,
913 -72, -72, -72, -72, -72, -72, -72, -72, -72, -72,
914
915 -72, -72, -72, -72, -72, -72, -72, -72, -72, -72,
916 -72, -72, -72, -72, -72, -72, -72, -72, -72
917 },
918
919 {
920 9, -73, -73, -73, -73, -73, -73, -73, -73, -73,
921 -73, -73, -73, -73, -73, -73, -73, -73, -73, -73,
922 -73, -73, -73, -73, -73, -73, -73, -73, -73, -73,
923 -73, -73, -73, -73, -73, -73, -73, -73, -73
924 },
925
926 {
927 9, -74, -74, -74, -74, -74, -74, -74, -74, -74,
928 -74, -74, -74, -74, -74, -74, -74, -74, -74, -74,
929 -74, -74, -74, -74, -74, -74, -74, -74, -74, -74,
930 -74, -74, -74, -74, -74, -74, -74, -74, -74
931
932 },
933
934 {
935 9, -75, -75, -75, -75, -75, -75, -75, -75, -75,
936 -75, -75, -75, -75, -75, -75, -75, -75, -75, -75,
937 -75, -75, -75, -75, -75, -75, -75, -75, -75, -75,
938 -75, -75, -75, -75, -75, -75, -75, -75, -75
939 },
940
941 {
942 9, 76, 76, -76, 76, 76, 76, 76, 76, 76,
943 76, 76, 76, 76, 76, 76, 76, 76, 76, 76,
944 76, 76, 76, 76, 76, 76, 76, 76, 76, 76,
945 76, 76, 76, 76, 76, 76, 76, 76, 76
946 },
947
948 {
949 9, -77, 83, -77, -77, -77, -77, -77, -77, -77,
950 -77, -77, -77, -77, -77, -77, -77, -77, -77, -77,
951
952 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
953 49, 49, 49, 49, 49, 49, 49, 49, 49
954 },
955
956 {
957 9, -78, -78, -78, -78, -78, -78, -78, -78, -78,
958 -78, -78, -78, -78, -78, -78, -78, -78, -78, -78,
959 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
960 49, 49, 49, 84, 49, 49, 49, 49, 49
961 },
962
963 {
964 9, -79, -79, -79, -79, -79, -79, -79, -79, -79,
965 -79, -79, -79, -79, -79, -79, -79, -79, -79, -79,
966 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
967 49, 49, 49, 85, 49, 49, 49, 49, 49
968
969 },
970
971 {
972 9, -80, -80, -80, -80, -80, -80, -80, -80, -80,
973 -80, -80, -80, -80, -80, -80, -80, -80, -80, -80,
974 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
975 49, 49, 86, 49, 49, 49, 49, 49, 49
976 },
977
978 {
979 9, -81, -81, -81, -81, -81, -81, -81, -81, -81,
980 -81, -81, -81, -81, -81, -81, -81, -81, -81, -81,
981 49, 49, 49, 49, 87, 49, 49, 49, 49, 49,
982 49, 49, 49, 49, 49, 49, 49, 49, 49
983 },
984
985 {
986 9, -82, 88, -82, -82, -82, -82, -82, -82, -82,
987 -82, -82, -82, -82, -82, -82, -82, -82, -82, -82,
988
989 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
990 49, 49, 49, 49, 49, 49, 49, 49, 49
991 },
992
993 {
994 9, -83, 83, -83, -83, -83, -83, -83, -83, -83,
995 -83, -83, -83, -83, -83, -83, -83, -83, -83, -83,
996 -83, -83, -83, -83, -83, -83, -83, -83, -83, -83,
997 -83, -83, -83, -83, -83, -83, -83, -83, -83
998 },
999
1000 {
1001 9, -84, 89, -84, -84, -84, -84, -84, -84, -84,
1002 -84, -84, -84, -84, -84, -84, -84, -84, -84, -84,
1003 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
1004 49, 49, 49, 49, 49, 49, 49, 49, 49
1005
1006 },
1007
1008 {
1009 9, -85, -85, -85, -85, -85, -85, -85, -85, -85,
1010 -85, -85, -85, -85, -85, -85, -85, -85, -85, -85,
1011 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
1012 49, 49, 49, 49, 49, 49, 49, 90, 49
1013 },
1014
1015 {
1016 9, -86, -86, -86, -86, -86, -86, -86, -86, -86,
1017 -86, -86, -86, -86, -86, -86, -86, -86, -86, -86,
1018 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
1019 49, 49, 49, 49, 91, 49, 49, 49, 49
1020 },
1021
1022 {
1023 9, -87, -87, -87, -87, -87, -87, -87, -87, -87,
1024 -87, -87, -87, -87, -87, -87, -87, -87, -87, -87,
1025
1026 49, 49, 49, 49, 49, 49, 49, 49, 49, 92,
1027 49, 49, 49, 49, 49, 49, 49, 49, 49
1028 },
1029
1030 {
1031 9, -88, 88, -88, -88, -88, -88, -88, -88, -88,
1032 -88, -88, -88, -88, -88, -88, -88, -88, -88, -88,
1033 -88, -88, -88, -88, -88, -88, -88, -88, -88, -88,
1034 -88, -88, -88, -88, -88, -88, -88, -88, -88
1035 },
1036
1037 {
1038 9, -89, 89, -89, -89, -89, -89, -89, -89, -89,
1039 -89, -89, -89, -89, -89, -89, -89, -89, -89, -89,
1040 -89, -89, -89, -89, -89, -89, -89, -89, -89, -89,
1041 -89, -89, -89, -89, -89, -89, -89, -89, -89
1042
1043 },
1044
1045 {
1046 9, -90, -90, -90, -90, -90, -90, -90, -90, -90,
1047 -90, -90, -90, -90, -90, -90, -90, -90, -90, -90,
1048 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
1049 49, 49, 49, 49, 49, 49, 93, 49, 49
1050 },
1051
1052 {
1053 9, -91, -91, -91, -91, -91, -91, -91, -91, -91,
1054 -91, -91, -91, -91, -91, -91, -91, -91, -91, -91,
1055 49, 49, 49, 49, 94, 49, 49, 49, 49, 49,
1056 49, 49, 49, 49, 49, 49, 49, 49, 49
1057 },
1058
1059 {
1060 9, -92, 95, -92, -92, -92, -92, -92, -92, -92,
1061 -92, -92, -92, -92, -92, -92, -92, -92, -92, -92,
1062
1063 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
1064 49, 49, 49, 49, 49, 49, 49, 49, 49
1065 },
1066
1067 {
1068 9, -93, -93, -93, -93, -93, -93, -93, -93, -93,
1069 -93, -93, -93, -93, -93, -93, -93, -93, -93, -93,
1070 49, 49, 49, 49, 96, 49, 49, 49, 49, 49,
1071 49, 49, 49, 49, 49, 49, 49, 49, 49
1072 },
1073
1074 {
1075 9, -94, 97, -94, -94, -94, -94, -94, -94, -94,
1076 -94, -94, -94, -94, -94, -94, -94, -94, -94, -94,
1077 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
1078 49, 49, 49, 49, 49, 49, 49, 49, 49
1079
1080 },
1081
1082 {
1083 9, -95, 95, -95, -95, -95, -95, -95, -95, -95,
1084 -95, -95, -95, -95, -95, -95, -95, -95, -95, -95,
1085 -95, -95, -95, -95, -95, -95, -95, -95, -95, -95,
1086 -95, -95, -95, -95, -95, -95, -95, -95, -95
1087 },
1088
1089 {
1090 9, -96, 98, -96, -96, -96, -96, -96, -96, -96,
1091 -96, -96, -96, -96, -96, -96, -96, -96, -96, -96,
1092 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
1093 49, 49, 49, 49, 49, 49, 49, 49, 49
1094 },
1095
1096 {
1097 9, -97, 97, -97, -97, -97, -97, -97, -97, -97,
1098 -97, -97, -97, -97, -97, -97, -97, -97, -97, -97,
1099
1100 -97, -97, -97, -97, -97, -97, -97, -97, -97, -97,
1101 -97, -97, -97, -97, -97, -97, -97, -97, -97
1102 },
1103
1104 {
1105 9, -98, 98, -98, -98, -98, -98, -98, -98, -98,
1106 -98, -98, -98, -98, -98, -98, -98, -98, -98, -98,
1107 -98, -98, -98, -98, -98, -98, -98, -98, -98, -98,
1108 -98, -98, -98, -98, -98, -98, -98, -98, -98
1109 },
1110
1111 } ;
1112
1113static yy_state_type yy_get_previous_state (void );
1114static yy_state_type yy_try_NUL_trans (yy_state_type current_state );
1115static int yy_get_next_buffer (void );
1116static void yy_fatal_error (yyconst char msg[] );
1117
1118/* Done after the current pattern has been matched and before the
1119 * corresponding action - sets up sensors_yytext.
1120 */
1121#define YY_DO_BEFORE_ACTION \
1122 (yytext_ptr) = yy_bp; \
1123 sensors_yyleng = (size_t) (yy_cp - yy_bp); \
1124 (yy_hold_char) = *yy_cp; \
1125 *yy_cp = '\0'; \
1126 (yy_c_buf_p) = yy_cp;
1127
1128#define YY_NUM_RULES 50
1129#define YY_END_OF_BUFFER 51
1130/* This struct is not used in this scanner,
1131 but its presence is necessary. */
1132struct yy_trans_info
1133 {
1134 flex_int32_t yy_verify;
1135 flex_int32_t yy_nxt;
1136 };
1137static yyconst flex_int16_t yy_accept[99] =
1138 { 0,
1139 0, 0, 0, 0, 0, 0, 13, 13, 51, 12,
1140 1, 2, 3, 11, 11, 11, 11, 11, 11, 33,
1141 15, 16, 31, 18, 25, 26, 23, 21, 27, 22,
1142 33, 24, 20, 28, 32, 33, 29, 30, 49, 36,
1143 39, 48, 13, 14, 1, 2, 3, 4, 11, 11,
1144 11, 11, 11, 11, 11, 15, 18, 19, 20, 34,
1145 20, 32, 35, 17, 49, 38, 47, 37, 40, 41,
1146 42, 43, 44, 45, 46, 13, 8, 11, 11, 11,
1147 11, 6, 8, 9, 11, 11, 11, 6, 9, 11,
1148 11, 5, 11, 10, 5, 7, 10, 7
1149
1150 } ;
1151
1152static yyconst flex_int32_t yy_ec[256] =
1153 { 0,
1154 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
1155 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
1156 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1157 1, 2, 1, 4, 5, 1, 1, 1, 1, 6,
1158 7, 8, 9, 10, 11, 12, 13, 14, 14, 14,
1159 14, 14, 14, 14, 14, 14, 14, 1, 1, 1,
1160 1, 1, 1, 15, 16, 16, 16, 16, 16, 16,
1161 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
1162 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
1163 1, 17, 1, 18, 16, 19, 20, 21, 22, 23,
1164
1165 24, 25, 26, 27, 28, 23, 23, 29, 30, 31,
1166 32, 33, 23, 34, 35, 36, 37, 38, 23, 23,
1167 23, 23, 1, 1, 1, 1, 1, 1, 1, 1,
1168 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1169 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1170 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1171 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1172 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1173 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1174 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1175
1176 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1177 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1178 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1179 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1180 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1181 1, 1, 1, 1, 1
1182 } ;
1183
1184extern int sensors_yy_flex_debug;
1185int sensors_yy_flex_debug = 0;
1186
1187/* The intent behind this definition is that it'll catch
1188 * any uses of REJECT which flex missed.
1189 */
1190#define REJECT reject_used_but_not_detected
1191#define yymore() yymore_used_but_not_detected
1192#define YY_MORE_ADJ 0
1193#define YY_RESTORE_YY_MORE_OFFSET
1194char *sensors_yytext;
1195#line 1 "lib/conf-lex.l"
1196#line 2 "lib/conf-lex.l"
1197/*
1198 conf-lex.l - Part of libsensors, a Linux library for reading sensor data.
1199 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
1200
1201 This library is free software; you can redistribute it and/or
1202 modify it under the terms of the GNU Lesser General Public
1203 License as published by the Free Software Foundation; either
1204 version 2.1 of the License, or (at your option) any later version.
1205
1206 This library is distributed in the hope that it will be useful,
1207 but WITHOUT ANY WARRANTY; without even the implied warranty of
1208 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1209 GNU Lesser General Public License for more details.
1210
1211 You should have received a copy of the GNU General Public License
1212 along with this program; if not, write to the Free Software
1213 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
1214 MA 02110-1301 USA.
1215*/
1216
1217#include <stdlib.h>
1218#include <string.h>
1219
1220#include "general.h"
1221#include "data.h"
1222#include "conf-parse.h"
1223#include "error.h"
1224#include "scanner.h"
1225
1226static int buffer_count;
1227static int buffer_max;
1228static char *buffer;
1229
1230char sensors_lex_error[100];
1231
1232const char *sensors_yyfilename;
1233int sensors_yylineno;
1234
1235#define buffer_malloc() sensors_malloc_array(&buffer,&buffer_count,\
1236 &buffer_max,1)
1237#define buffer_free() sensors_free_array(&buffer,&buffer_count,\
1238 &buffer_max)
1239#define buffer_add_char(c) sensors_add_array_el(c,&buffer,\
1240 &buffer_count,\
1241 &buffer_max,1)
1242#define buffer_add_string(s) sensors_add_array_els(s,strlen(s),\
1243 &buffer, \
1244 &buffer_count,&buffer_max,1)
1245
1246/* Scanner for configuration files */
1247/* All states are exclusive */
1248
1249
1250
1251/* Any whitespace-like character */
1252/* Note: `10', `10.4' and `.4' are valid, `10.' is not */
1253/* Only positive whole numbers are recognized here */
1254#line 1255 "<stdout>"
1255
1256#define INITIAL 0
1257#define MIDDLE 1
1258#define STRING 2
1259#define ERR 3
1260
1261#ifndef YY_NO_UNISTD_H
1262/* Special case for "unistd.h", since it is non-ANSI. We include it way
1263 * down here because we want the user's section 1 to have been scanned first.
1264 * The user has a chance to override it with an option.
1265 */
1266#include <unistd.h>
1267#endif
1268
1269#ifndef YY_EXTRA_TYPE
1270#define YY_EXTRA_TYPE void *
1271#endif
1272
1273static int yy_init_globals (void );
1274
1275/* Accessor methods to globals.
1276 These are made visible to non-reentrant scanners for convenience. */
1277
1278int sensors_yylex_destroy (void );
1279
1280int sensors_yyget_debug (void );
1281
1282void sensors_yyset_debug (int debug_flag );
1283
1284YY_EXTRA_TYPE sensors_yyget_extra (void );
1285
1286void sensors_yyset_extra (YY_EXTRA_TYPE user_defined );
1287
1288FILE *sensors_yyget_in (void );
1289
1290void sensors_yyset_in (FILE * in_str );
1291
1292FILE *sensors_yyget_out (void );
1293
1294void sensors_yyset_out (FILE * out_str );
1295
1296int sensors_yyget_leng (void );
1297
1298char *sensors_yyget_text (void );
1299
1300int sensors_yyget_lineno (void );
1301
1302void sensors_yyset_lineno (int line_number );
1303
1304/* Macros after this point can all be overridden by user definitions in
1305 * section 1.
1306 */
1307
1308#ifndef YY_SKIP_YYWRAP
1309#ifdef __cplusplus
1310extern "C" int sensors_yywrap (void );
1311#else
1312extern int sensors_yywrap (void );
1313#endif
1314#endif
1315
1316#ifndef yytext_ptr
1317static void yy_flex_strncpy (char *,yyconst char *,int );
1318#endif
1319
1320#ifdef YY_NEED_STRLEN
1321static int yy_flex_strlen (yyconst char * );
1322#endif
1323
1324#ifndef YY_NO_INPUT
1325
1326#ifdef __cplusplus
1327static int yyinput (void );
1328#else
1329static int input (void );
1330#endif
1331
1332#endif
1333
1334/* Amount of stuff to slurp up with each read. */
1335#ifndef YY_READ_BUF_SIZE
1336#ifdef __ia64__
1337/* On IA-64, the buffer size is 16k, not 8k */
1338#define YY_READ_BUF_SIZE 16384
1339#else
1340#define YY_READ_BUF_SIZE 8192
1341#endif /* __ia64__ */
1342#endif
1343
1344/* Copy whatever the last rule matched to the standard output. */
1345#ifndef ECHO
1346/* This used to be an fputs(), but since the string might contain NUL's,
1347 * we now use fwrite().
1348 */
1349#define ECHO do { if (fwrite( sensors_yytext, sensors_yyleng, 1, sensors_yyout )) {} } while (0)
1350#endif
1351
1352/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
1353 * is returned in "result".
1354 */
1355#ifndef YY_INPUT
1356#define YY_INPUT(buf,result,max_size) \
1357 if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
1358 { \
1359 int c = '*'; \
1360 size_t n; \
1361 for ( n = 0; n < max_size && \
1362 (c = getc( sensors_yyin )) != EOF && c != '\n'; ++n ) \
1363 buf[n] = (char) c; \
1364 if ( c == '\n' ) \
1365 buf[n++] = (char) c; \
1366 if ( c == EOF && ferror( sensors_yyin ) ) \
1367 YY_FATAL_ERROR( "input in flex scanner failed" ); \
1368 result = n; \
1369 } \
1370 else \
1371 { \
1372 errno=0; \
1373 while ( (result = fread(buf, 1, max_size, sensors_yyin))==0 && ferror(sensors_yyin)) \
1374 { \
1375 if( errno != EINTR) \
1376 { \
1377 YY_FATAL_ERROR( "input in flex scanner failed" ); \
1378 break; \
1379 } \
1380 errno=0; \
1381 clearerr(sensors_yyin); \
1382 } \
1383 }\
1384\
1385
1386#endif
1387
1388/* No semi-colon after return; correct usage is to write "yyterminate();" -
1389 * we don't want an extra ';' after the "return" because that will cause
1390 * some compilers to complain about unreachable statements.
1391 */
1392#ifndef yyterminate
1393#define yyterminate() return YY_NULL
1394#endif
1395
1396/* Number of entries by which start-condition stack grows. */
1397#ifndef YY_START_STACK_INCR
1398#define YY_START_STACK_INCR 25
1399#endif
1400
1401/* Report a fatal error. */
1402#ifndef YY_FATAL_ERROR
1403#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
1404#endif
1405
1406/* end tables serialization structures and prototypes */
1407
1408/* Default declaration of generated scanner - a define so the user can
1409 * easily add parameters.
1410 */
1411#ifndef YY_DECL
1412#define YY_DECL_IS_OURS 1
1413
1414extern int sensors_yylex (void);
1415
1416#define YY_DECL int sensors_yylex (void)
1417#endif /* !YY_DECL */
1418
1419/* Code executed at the beginning of each rule, after sensors_yytext and sensors_yyleng
1420 * have been set up.
1421 */
1422#ifndef YY_USER_ACTION
1423#define YY_USER_ACTION
1424#endif
1425
1426/* Code executed at the end of each rule. */
1427#ifndef YY_BREAK
1428#define YY_BREAK break;
1429#endif
1430
1431#define YY_RULE_SETUP \
1432 YY_USER_ACTION
1433
1434/** The main scanner function which does all the work.
1435 */
1436YY_DECL
1437{
1438 register yy_state_type yy_current_state;
1439 register char *yy_cp, *yy_bp;
1440 register int yy_act;
1441
1442#line 80 "lib/conf-lex.l"
1443
1444
1445 /*
1446 * STATE: INITIAL
1447 */
1448
1449#line 1450 "<stdout>"
1450
1451 if ( !(yy_init) )
1452 {
1453 (yy_init) = 1;
1454
1455#ifdef YY_USER_INIT
1456 YY_USER_INIT;
1457#endif
1458
1459 if ( ! (yy_start) )
1460 (yy_start) = 1; /* first start state */
1461
1462 if ( ! sensors_yyin )
1463 sensors_yyin = stdin;
1464
1465 if ( ! sensors_yyout )
1466 sensors_yyout = stdout;
1467
1468 if ( ! YY_CURRENT_BUFFER ) {
1469 sensors_yyensure_buffer_stack ();
1470 YY_CURRENT_BUFFER_LVALUE =
1471 sensors_yy_create_buffer(sensors_yyin,YY_BUF_SIZE );
1472 }
1473
1474 sensors_yy_load_buffer_state( );
1475 }
1476
1477 while ( 1 ) /* loops until end-of-file is reached */
1478 {
1479 yy_cp = (yy_c_buf_p);
1480
1481 /* Support of sensors_yytext. */
1482 *yy_cp = (yy_hold_char);
1483
1484 /* yy_bp points to the position in yy_ch_buf of the start of
1485 * the current run.
1486 */
1487 yy_bp = yy_cp;
1488
1489 yy_current_state = (yy_start);
1490yy_match:
1491 while ( (yy_current_state = yy_nxt[yy_current_state][ yy_ec[YY_SC_TO_UI(*yy_cp)] ]) > 0 )
1492 ++yy_cp;
1493
1494 yy_current_state = -yy_current_state;
1495
1496yy_find_action:
1497 yy_act = yy_accept[yy_current_state];
1498
1499 YY_DO_BEFORE_ACTION;
1500
1501do_action: /* This label is used only to access EOF actions. */
1502
1503 switch ( yy_act )
1504 { /* beginning of action switch */
1505
1506case YY_STATE_EOF(INITIAL):
1507#line 88 "lib/conf-lex.l"
1508{ /* EOF from this state terminates */
1509 return 0;
1510 }
1511 YY_BREAK
1512case 1:
1513YY_RULE_SETUP
1514#line 92 "lib/conf-lex.l"
1515; /* eat as many blanks as possible at once */
1516 YY_BREAK
1517case 2:
1518/* rule 2 can match eol */
1519YY_RULE_SETUP
1520#line 94 "lib/conf-lex.l"
1521{ /* eat a bare newline (possibly preceded by blanks) */
1522 sensors_yylineno++;
1523 }
1524 YY_BREAK
1525/* comments */
1526case 3:
1527YY_RULE_SETUP
1528#line 100 "lib/conf-lex.l"
1529; /* eat the rest of the line after comment char */
1530 YY_BREAK
1531case 4:
1532/* rule 4 can match eol */
1533YY_RULE_SETUP
1534#line 102 "lib/conf-lex.l"
1535{ /* eat the rest of the line after comment char */
1536 sensors_yylineno++;
1537 }
1538 YY_BREAK
1539/*
1540 * Keywords must be followed by whitespace - eat that too.
1541 * If there isn't trailing whitespace, we still need to
1542 * accept it as lexically correct (even though the parser
1543 * will reject it anyway.)
1544 */
1545case 5:
1546YY_RULE_SETUP
1547#line 113 "lib/conf-lex.l"
1548{
1549 sensors_yylval.line.filename = sensors_yyfilename;
1550 sensors_yylval.line.lineno = sensors_yylineno;
1551 BEGIN(MIDDLE);
1552 return LABEL;
1553 }
1554 YY_BREAK
1555case 6:
1556YY_RULE_SETUP
1557#line 120 "lib/conf-lex.l"
1558{
1559 sensors_yylval.line.filename = sensors_yyfilename;
1560 sensors_yylval.line.lineno = sensors_yylineno;
1561 BEGIN(MIDDLE);
1562 return SET;
1563 }
1564 YY_BREAK
1565case 7:
1566YY_RULE_SETUP
1567#line 127 "lib/conf-lex.l"
1568{
1569 sensors_yylval.line.filename = sensors_yyfilename;
1570 sensors_yylval.line.lineno = sensors_yylineno;
1571 BEGIN(MIDDLE);
1572 return COMPUTE;
1573 }
1574 YY_BREAK
1575case 8:
1576YY_RULE_SETUP
1577#line 134 "lib/conf-lex.l"
1578{
1579 sensors_yylval.line.filename = sensors_yyfilename;
1580 sensors_yylval.line.lineno = sensors_yylineno;
1581 BEGIN(MIDDLE);
1582 return BUS;
1583 }
1584 YY_BREAK
1585case 9:
1586YY_RULE_SETUP
1587#line 141 "lib/conf-lex.l"
1588{
1589 sensors_yylval.line.filename = sensors_yyfilename;
1590 sensors_yylval.line.lineno = sensors_yylineno;
1591 BEGIN(MIDDLE);
1592 return CHIP;
1593 }
1594 YY_BREAK
1595case 10:
1596YY_RULE_SETUP
1597#line 148 "lib/conf-lex.l"
1598{
1599 sensors_yylval.line.filename = sensors_yyfilename;
1600 sensors_yylval.line.lineno = sensors_yylineno;
1601 BEGIN(MIDDLE);
1602 return IGNORE;
1603 }
1604 YY_BREAK
1605/* Anything else at the beginning of a line is an error */
1606case 11:
1607#line 158 "lib/conf-lex.l"
1608case 12:
1609YY_RULE_SETUP
1610#line 158 "lib/conf-lex.l"
1611{
1612 BEGIN(ERR);
1613 strcpy(sensors_lex_error,"Invalid keyword");
1614 return ERROR;
1615 }
1616 YY_BREAK
1617
1618/*
1619 * STATE: ERROR
1620 */
1621
1622case 13:
1623YY_RULE_SETUP
1624#line 171 "lib/conf-lex.l"
1625; /* eat whatever is left on this line */
1626 YY_BREAK
1627case 14:
1628/* rule 14 can match eol */
1629YY_RULE_SETUP
1630#line 173 "lib/conf-lex.l"
1631{
1632 BEGIN(INITIAL);
1633 sensors_yylineno++;
1634 return EOL;
1635 }
1636 YY_BREAK
1637
1638/*
1639 * STATE: MIDDLE
1640 */
1641
1642case 15:
1643YY_RULE_SETUP
1644#line 186 "lib/conf-lex.l"
1645; /* eat as many blanks as possible at once */
1646 YY_BREAK
1647case 16:
1648/* rule 16 can match eol */
1649YY_RULE_SETUP
1650#line 188 "lib/conf-lex.l"
1651{ /* newline here sends EOL token to parser */
1652 BEGIN(INITIAL);
1653 sensors_yylineno++;
1654 return EOL;
1655 }
1656 YY_BREAK
1657case YY_STATE_EOF(MIDDLE):
1658#line 194 "lib/conf-lex.l"
1659{ /* EOF here sends EOL token to parser also */
1660 BEGIN(INITIAL);
1661 return EOL;
1662 }
1663 YY_BREAK
1664case 17:
1665/* rule 17 can match eol */
1666YY_RULE_SETUP
1667#line 199 "lib/conf-lex.l"
1668{ /* eat an escaped newline with no state change */
1669 sensors_yylineno++;
1670 }
1671 YY_BREAK
1672/* comments */
1673case 18:
1674YY_RULE_SETUP
1675#line 205 "lib/conf-lex.l"
1676; /* eat the rest of the line after comment char */
1677 YY_BREAK
1678case 19:
1679/* rule 19 can match eol */
1680YY_RULE_SETUP
1681#line 207 "lib/conf-lex.l"
1682{ /* eat the rest of the line after comment char */
1683 BEGIN(INITIAL);
1684 sensors_yylineno++;
1685 return EOL;
1686 }
1687 YY_BREAK
1688/* A number */
1689case 20:
1690YY_RULE_SETUP
1691#line 215 "lib/conf-lex.l"
1692{
1693 sensors_yylval.value = atof(sensors_yytext);
1694 return FLOAT;
1695 }
1696 YY_BREAK
1697/* Some operators */
1698case 21:
1699YY_RULE_SETUP
1700#line 222 "lib/conf-lex.l"
1701return '+';
1702 YY_BREAK
1703case 22:
1704YY_RULE_SETUP
1705#line 223 "lib/conf-lex.l"
1706return '-';
1707 YY_BREAK
1708case 23:
1709YY_RULE_SETUP
1710#line 224 "lib/conf-lex.l"
1711return '*';
1712 YY_BREAK
1713case 24:
1714YY_RULE_SETUP
1715#line 225 "lib/conf-lex.l"
1716return '/';
1717 YY_BREAK
1718case 25:
1719YY_RULE_SETUP
1720#line 226 "lib/conf-lex.l"
1721return '(';
1722 YY_BREAK
1723case 26:
1724YY_RULE_SETUP
1725#line 227 "lib/conf-lex.l"
1726return ')';
1727 YY_BREAK
1728case 27:
1729YY_RULE_SETUP
1730#line 228 "lib/conf-lex.l"
1731return ',';
1732 YY_BREAK
1733case 28:
1734YY_RULE_SETUP
1735#line 229 "lib/conf-lex.l"
1736return '@';
1737 YY_BREAK
1738case 29:
1739YY_RULE_SETUP
1740#line 230 "lib/conf-lex.l"
1741return '^';
1742 YY_BREAK
1743case 30:
1744YY_RULE_SETUP
1745#line 231 "lib/conf-lex.l"
1746return '`';
1747 YY_BREAK
1748/* Quoted string */
1749case 31:
1750YY_RULE_SETUP
1751#line 235 "lib/conf-lex.l"
1752{
1753 buffer_malloc();
1754 BEGIN(STRING);
1755 }
1756 YY_BREAK
1757/* A normal, unquoted identifier */
1758case 32:
1759YY_RULE_SETUP
1760#line 242 "lib/conf-lex.l"
1761{
1762 sensors_yylval.name = strdup(sensors_yytext);
1763 if (! sensors_yylval.name)
1764 sensors_fatal_error("conf-lex.l",
1765 "Allocating a new string");
1766
1767 return NAME;
1768 }
1769 YY_BREAK
1770/* anything else is bogus */
1771case 33:
1772#line 254 "lib/conf-lex.l"
1773case 34:
1774#line 255 "lib/conf-lex.l"
1775case 35:
1776YY_RULE_SETUP
1777#line 255 "lib/conf-lex.l"
1778{
1779 BEGIN(ERR);
1780 return ERROR;
1781 }
1782 YY_BREAK
1783
1784/*
1785 * STATE: STRING
1786 */
1787
1788/* Oops, newline or EOF while in a string is not good */
1789case 36:
1790/* rule 36 can match eol */
1791#line 270 "lib/conf-lex.l"
1792case 37:
1793/* rule 37 can match eol */
1794YY_RULE_SETUP
1795#line 270 "lib/conf-lex.l"
1796{
1797 buffer_add_char("\0");
1798 strcpy(sensors_lex_error,
1799 "No matching double quote.");
1800 buffer_free();
1801 yyless(0);
1802 BEGIN(ERR);
1803 return ERROR;
1804 }
1805 YY_BREAK
1806case YY_STATE_EOF(STRING):
1807#line 280 "lib/conf-lex.l"
1808{
1809 strcpy(sensors_lex_error,
1810 "Reached end-of-file without a matching double quote.");
1811 buffer_free();
1812 BEGIN(MIDDLE);
1813 return ERROR;
1814 }
1815 YY_BREAK
1816/* At the end */
1817case 38:
1818YY_RULE_SETUP
1819#line 290 "lib/conf-lex.l"
1820{
1821 buffer_add_char("\0");
1822 strcpy(sensors_lex_error,
1823 "Quoted strings must be separated by whitespace.");
1824 buffer_free();
1825 BEGIN(ERR);
1826 return ERROR;
1827 }
1828 YY_BREAK
1829case 39:
1830YY_RULE_SETUP
1831#line 299 "lib/conf-lex.l"
1832{
1833 buffer_add_char("\0");
1834 sensors_yylval.name = strdup(buffer);
1835 if (! sensors_yylval.name)
1836 sensors_fatal_error("conf-lex.l",
1837 "Allocating a new string");
1838 buffer_free();
1839 BEGIN(MIDDLE);
1840 return NAME;
1841 }
1842 YY_BREAK
1843case 40:
1844YY_RULE_SETUP
1845#line 310 "lib/conf-lex.l"
1846buffer_add_char("\a");
1847 YY_BREAK
1848case 41:
1849YY_RULE_SETUP
1850#line 311 "lib/conf-lex.l"
1851buffer_add_char("\b");
1852 YY_BREAK
1853case 42:
1854YY_RULE_SETUP
1855#line 312 "lib/conf-lex.l"
1856buffer_add_char("\f");
1857 YY_BREAK
1858case 43:
1859YY_RULE_SETUP
1860#line 313 "lib/conf-lex.l"
1861buffer_add_char("\n");
1862 YY_BREAK
1863case 44:
1864YY_RULE_SETUP
1865#line 314 "lib/conf-lex.l"
1866buffer_add_char("\r");
1867 YY_BREAK
1868case 45:
1869YY_RULE_SETUP
1870#line 315 "lib/conf-lex.l"
1871buffer_add_char("\t");
1872 YY_BREAK
1873case 46:
1874YY_RULE_SETUP
1875#line 316 "lib/conf-lex.l"
1876buffer_add_char("\v");
1877 YY_BREAK
1878/* Other escapes: just copy the character behind the slash */
1879case 47:
1880YY_RULE_SETUP
1881#line 320 "lib/conf-lex.l"
1882{
1883 buffer_add_char(&sensors_yytext[1]);
1884 }
1885 YY_BREAK
1886/* Anything else (including a bare '\' which may be followed by EOF) */
1887case 48:
1888#line 327 "lib/conf-lex.l"
1889case 49:
1890YY_RULE_SETUP
1891#line 327 "lib/conf-lex.l"
1892{
1893 buffer_add_string(sensors_yytext);
1894 }
1895 YY_BREAK
1896
1897case 50:
1898YY_RULE_SETUP
1899#line 332 "lib/conf-lex.l"
1900YY_FATAL_ERROR( "flex scanner jammed" );
1901 YY_BREAK
1902#line 1903 "<stdout>"
1903 case YY_STATE_EOF(ERR):
1904 yyterminate();
1905
1906 case YY_END_OF_BUFFER:
1907 {
1908 /* Amount of text matched not including the EOB char. */
1909 int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
1910
1911 /* Undo the effects of YY_DO_BEFORE_ACTION. */
1912 *yy_cp = (yy_hold_char);
1913 YY_RESTORE_YY_MORE_OFFSET
1914
1915 if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
1916 {
1917 /* We're scanning a new file or input source. It's
1918 * possible that this happened because the user
1919 * just pointed sensors_yyin at a new source and called
1920 * sensors_yylex(). If so, then we have to assure
1921 * consistency between YY_CURRENT_BUFFER and our
1922 * globals. Here is the right place to do so, because
1923 * this is the first action (other than possibly a
1924 * back-up) that will match for the new input source.
1925 */
1926 (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
1927 YY_CURRENT_BUFFER_LVALUE->yy_input_file = sensors_yyin;
1928 YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
1929 }
1930
1931 /* Note that here we test for yy_c_buf_p "<=" to the position
1932 * of the first EOB in the buffer, since yy_c_buf_p will
1933 * already have been incremented past the NUL character
1934 * (since all states make transitions on EOB to the
1935 * end-of-buffer state). Contrast this with the test
1936 * in input().
1937 */
1938 if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
1939 { /* This was really a NUL. */
1940 yy_state_type yy_next_state;
1941
1942 (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
1943
1944 yy_current_state = yy_get_previous_state( );
1945
1946 /* Okay, we're now positioned to make the NUL
1947 * transition. We couldn't have
1948 * yy_get_previous_state() go ahead and do it
1949 * for us because it doesn't know how to deal
1950 * with the possibility of jamming (and we don't
1951 * want to build jamming into it because then it
1952 * will run more slowly).
1953 */
1954
1955 yy_next_state = yy_try_NUL_trans( yy_current_state );
1956
1957 yy_bp = (yytext_ptr) + YY_MORE_ADJ;
1958
1959 if ( yy_next_state )
1960 {
1961 /* Consume the NUL. */
1962 yy_cp = ++(yy_c_buf_p);
1963 yy_current_state = yy_next_state;
1964 goto yy_match;
1965 }
1966
1967 else
1968 {
1969 yy_cp = (yy_c_buf_p);
1970 goto yy_find_action;
1971 }
1972 }
1973
1974 else switch ( yy_get_next_buffer( ) )
1975 {
1976 case EOB_ACT_END_OF_FILE:
1977 {
1978 (yy_did_buffer_switch_on_eof) = 0;
1979
1980 if ( sensors_yywrap( ) )
1981 {
1982 /* Note: because we've taken care in
1983 * yy_get_next_buffer() to have set up
1984 * sensors_yytext, we can now set up
1985 * yy_c_buf_p so that if some total
1986 * hoser (like flex itself) wants to
1987 * call the scanner after we return the
1988 * YY_NULL, it'll still work - another
1989 * YY_NULL will get returned.
1990 */
1991 (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
1992
1993 yy_act = YY_STATE_EOF(YY_START);
1994 goto do_action;
1995 }
1996
1997 else
1998 {
1999 if ( ! (yy_did_buffer_switch_on_eof) )
2000 YY_NEW_FILE;
2001 }
2002 break;
2003 }
2004
2005 case EOB_ACT_CONTINUE_SCAN:
2006 (yy_c_buf_p) =
2007 (yytext_ptr) + yy_amount_of_matched_text;
2008
2009 yy_current_state = yy_get_previous_state( );
2010
2011 yy_cp = (yy_c_buf_p);
2012 yy_bp = (yytext_ptr) + YY_MORE_ADJ;
2013 goto yy_match;
2014
2015 case EOB_ACT_LAST_MATCH:
2016 (yy_c_buf_p) =
2017 &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
2018
2019 yy_current_state = yy_get_previous_state( );
2020
2021 yy_cp = (yy_c_buf_p);
2022 yy_bp = (yytext_ptr) + YY_MORE_ADJ;
2023 goto yy_find_action;
2024 }
2025 break;
2026 }
2027
2028 default:
2029 YY_FATAL_ERROR(
2030 "fatal flex scanner internal error--no action found" );
2031 } /* end of action switch */
2032 } /* end of scanning one token */
2033} /* end of sensors_yylex */
2034
2035/* yy_get_next_buffer - try to read in a new buffer
2036 *
2037 * Returns a code representing an action:
2038 * EOB_ACT_LAST_MATCH -
2039 * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
2040 * EOB_ACT_END_OF_FILE - end of file
2041 */
2042static int yy_get_next_buffer (void)
2043{
2044 register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
2045 register char *source = (yytext_ptr);
2046 register int number_to_move, i;
2047 int ret_val;
2048
2049 if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
2050 YY_FATAL_ERROR(
2051 "fatal flex scanner internal error--end of buffer missed" );
2052
2053 if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
2054 { /* Don't try to fill the buffer, so this is an EOF. */
2055 if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
2056 {
2057 /* We matched a single character, the EOB, so
2058 * treat this as a final EOF.
2059 */
2060 return EOB_ACT_END_OF_FILE;
2061 }
2062
2063 else
2064 {
2065 /* We matched some text prior to the EOB, first
2066 * process it.
2067 */
2068 return EOB_ACT_LAST_MATCH;
2069 }
2070 }
2071
2072 /* Try to read more data. */
2073
2074 /* First move last chars to start of buffer. */
2075 number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
2076
2077 for ( i = 0; i < number_to_move; ++i )
2078 *(dest++) = *(source++);
2079
2080 if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
2081 /* don't do the read, it's not guaranteed to return an EOF,
2082 * just force an EOF
2083 */
2084 YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
2085
2086 else
2087 {
2088 int num_to_read =
2089 YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
2090
2091 while ( num_to_read <= 0 )
2092 { /* Not enough room in the buffer - grow it. */
2093
2094 /* just a shorter name for the current buffer */
2095 YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
2096
2097 int yy_c_buf_p_offset =
2098 (int) ((yy_c_buf_p) - b->yy_ch_buf);
2099
2100 if ( b->yy_is_our_buffer )
2101 {
2102 int new_size = b->yy_buf_size * 2;
2103
2104 if ( new_size <= 0 )
2105 b->yy_buf_size += b->yy_buf_size / 8;
2106 else
2107 b->yy_buf_size *= 2;
2108
2109 b->yy_ch_buf = (char *)
2110 /* Include room in for 2 EOB chars. */
2111 sensors_yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 );
2112 }
2113 else
2114 /* Can't grow it, we don't own it. */
2115 b->yy_ch_buf = 0;
2116
2117 if ( ! b->yy_ch_buf )
2118 YY_FATAL_ERROR(
2119 "fatal error - scanner input buffer overflow" );
2120
2121 (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
2122
2123 num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
2124 number_to_move - 1;
2125
2126 }
2127
2128 if ( num_to_read > YY_READ_BUF_SIZE )
2129 num_to_read = YY_READ_BUF_SIZE;
2130
2131 /* Read in more data. */
2132 YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
2133 (yy_n_chars), (size_t) num_to_read );
2134
2135 YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
2136 }
2137
2138 if ( (yy_n_chars) == 0 )
2139 {
2140 if ( number_to_move == YY_MORE_ADJ )
2141 {
2142 ret_val = EOB_ACT_END_OF_FILE;
2143 sensors_yyrestart(sensors_yyin );
2144 }
2145
2146 else
2147 {
2148 ret_val = EOB_ACT_LAST_MATCH;
2149 YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
2150 YY_BUFFER_EOF_PENDING;
2151 }
2152 }
2153
2154 else
2155 ret_val = EOB_ACT_CONTINUE_SCAN;
2156
2157 if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
2158 /* Extend the array by 50%, plus the number we really need. */
2159 yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
2160 YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) sensors_yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size );
2161 if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
2162 YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
2163 }
2164
2165 (yy_n_chars) += number_to_move;
2166 YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
2167 YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
2168
2169 (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
2170
2171 return ret_val;
2172}
2173
2174/* yy_get_previous_state - get the state just before the EOB char was reached */
2175
2176 static yy_state_type yy_get_previous_state (void)
2177{
2178 register yy_state_type yy_current_state;
2179 register char *yy_cp;
2180
2181 yy_current_state = (yy_start);
2182
2183 for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
2184 {
2185 yy_current_state = yy_nxt[yy_current_state][(*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1)];
2186 }
2187
2188 return yy_current_state;
2189}
2190
2191/* yy_try_NUL_trans - try to make a transition on the NUL character
2192 *
2193 * synopsis
2194 * next_state = yy_try_NUL_trans( current_state );
2195 */
2196 static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
2197{
2198 register int yy_is_jam;
2199
2200 yy_current_state = yy_nxt[yy_current_state][1];
2201 yy_is_jam = (yy_current_state <= 0);
2202
2203 return yy_is_jam ? 0 : yy_current_state;
2204}
2205
2206#ifndef YY_NO_INPUT
2207#ifdef __cplusplus
2208 static int yyinput (void)
2209#else
2210 static int input (void)
2211#endif
2212
2213{
2214 int c;
2215
2216 *(yy_c_buf_p) = (yy_hold_char);
2217
2218 if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
2219 {
2220 /* yy_c_buf_p now points to the character we want to return.
2221 * If this occurs *before* the EOB characters, then it's a
2222 * valid NUL; if not, then we've hit the end of the buffer.
2223 */
2224 if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
2225 /* This was really a NUL. */
2226 *(yy_c_buf_p) = '\0';
2227
2228 else
2229 { /* need more input */
2230 int offset = (yy_c_buf_p) - (yytext_ptr);
2231 ++(yy_c_buf_p);
2232
2233 switch ( yy_get_next_buffer( ) )
2234 {
2235 case EOB_ACT_LAST_MATCH:
2236 /* This happens because yy_g_n_b()
2237 * sees that we've accumulated a
2238 * token and flags that we need to
2239 * try matching the token before
2240 * proceeding. But for input(),
2241 * there's no matching to consider.
2242 * So convert the EOB_ACT_LAST_MATCH
2243 * to EOB_ACT_END_OF_FILE.
2244 */
2245
2246 /* Reset buffer status. */
2247 sensors_yyrestart(sensors_yyin );
2248
2249 /*FALLTHROUGH*/
2250
2251 case EOB_ACT_END_OF_FILE:
2252 {
2253 if ( sensors_yywrap( ) )
2254 return EOF;
2255
2256 if ( ! (yy_did_buffer_switch_on_eof) )
2257 YY_NEW_FILE;
2258#ifdef __cplusplus
2259 return yyinput();
2260#else
2261 return input();
2262#endif
2263 }
2264
2265 case EOB_ACT_CONTINUE_SCAN:
2266 (yy_c_buf_p) = (yytext_ptr) + offset;
2267 break;
2268 }
2269 }
2270 }
2271
2272 c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */
2273 *(yy_c_buf_p) = '\0'; /* preserve sensors_yytext */
2274 (yy_hold_char) = *++(yy_c_buf_p);
2275
2276 return c;
2277}
2278#endif /* ifndef YY_NO_INPUT */
2279
2280/** Immediately switch to a different input stream.
2281 * @param input_file A readable stream.
2282 *
2283 * @note This function does not reset the start condition to @c INITIAL .
2284 */
2285 void sensors_yyrestart (FILE * input_file )
2286{
2287
2288 if ( ! YY_CURRENT_BUFFER ){
2289 sensors_yyensure_buffer_stack ();
2290 YY_CURRENT_BUFFER_LVALUE =
2291 sensors_yy_create_buffer(sensors_yyin,YY_BUF_SIZE );
2292 }
2293
2294 sensors_yy_init_buffer(YY_CURRENT_BUFFER,input_file );
2295 sensors_yy_load_buffer_state( );
2296}
2297
2298/** Switch to a different input buffer.
2299 * @param new_buffer The new input buffer.
2300 *
2301 */
2302 void sensors_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer )
2303{
2304
2305 /* TODO. We should be able to replace this entire function body
2306 * with
2307 * sensors_yypop_buffer_state();
2308 * sensors_yypush_buffer_state(new_buffer);
2309 */
2310 sensors_yyensure_buffer_stack ();
2311 if ( YY_CURRENT_BUFFER == new_buffer )
2312 return;
2313
2314 if ( YY_CURRENT_BUFFER )
2315 {
2316 /* Flush out information for old buffer. */
2317 *(yy_c_buf_p) = (yy_hold_char);
2318 YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
2319 YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
2320 }
2321
2322 YY_CURRENT_BUFFER_LVALUE = new_buffer;
2323 sensors_yy_load_buffer_state( );
2324
2325 /* We don't actually know whether we did this switch during
2326 * EOF (sensors_yywrap()) processing, but the only time this flag
2327 * is looked at is after sensors_yywrap() is called, so it's safe
2328 * to go ahead and always set it.
2329 */
2330 (yy_did_buffer_switch_on_eof) = 1;
2331}
2332
2333static void sensors_yy_load_buffer_state (void)
2334{
2335 (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
2336 (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
2337 sensors_yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
2338 (yy_hold_char) = *(yy_c_buf_p);
2339}
2340
2341/** Allocate and initialize an input buffer state.
2342 * @param file A readable stream.
2343 * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
2344 *
2345 * @return the allocated buffer state.
2346 */
2347 YY_BUFFER_STATE sensors_yy_create_buffer (FILE * file, int size )
2348{
2349 YY_BUFFER_STATE b;
2350
2351 b = (YY_BUFFER_STATE) sensors_yyalloc(sizeof( struct yy_buffer_state ) );
2352 if ( ! b )
2353 YY_FATAL_ERROR( "out of dynamic memory in sensors_yy_create_buffer()" );
2354
2355 b->yy_buf_size = size;
2356
2357 /* yy_ch_buf has to be 2 characters longer than the size given because
2358 * we need to put in 2 end-of-buffer characters.
2359 */
2360 b->yy_ch_buf = (char *) sensors_yyalloc(b->yy_buf_size + 2 );
2361 if ( ! b->yy_ch_buf )
2362 YY_FATAL_ERROR( "out of dynamic memory in sensors_yy_create_buffer()" );
2363
2364 b->yy_is_our_buffer = 1;
2365
2366 sensors_yy_init_buffer(b,file );
2367
2368 return b;
2369}
2370
2371/** Destroy the buffer.
2372 * @param b a buffer created with sensors_yy_create_buffer()
2373 *
2374 */
2375 void sensors_yy_delete_buffer (YY_BUFFER_STATE b )
2376{
2377
2378 if ( ! b )
2379 return;
2380
2381 if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
2382 YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
2383
2384 if ( b->yy_is_our_buffer )
2385 sensors_yyfree((void *) b->yy_ch_buf );
2386
2387 sensors_yyfree((void *) b );
2388}
2389
2390#ifndef __cplusplus
2391extern int isatty (int );
2392#endif /* __cplusplus */
2393
2394/* Initializes or reinitializes a buffer.
2395 * This function is sometimes called more than once on the same buffer,
2396 * such as during a sensors_yyrestart() or at EOF.
2397 */
2398 static void sensors_yy_init_buffer (YY_BUFFER_STATE b, FILE * file )
2399
2400{
2401 int oerrno = errno;
2402
2403 sensors_yy_flush_buffer(b );
2404
2405 b->yy_input_file = file;
2406 b->yy_fill_buffer = 1;
2407
2408 /* If b is the current buffer, then sensors_yy_init_buffer was _probably_
2409 * called from sensors_yyrestart() or through yy_get_next_buffer.
2410 * In that case, we don't want to reset the lineno or column.
2411 */
2412 if (b != YY_CURRENT_BUFFER){
2413 b->yy_bs_lineno = 1;
2414 b->yy_bs_column = 0;
2415 }
2416
2417 b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
2418
2419 errno = oerrno;
2420}
2421
2422/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
2423 * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
2424 *
2425 */
2426 void sensors_yy_flush_buffer (YY_BUFFER_STATE b )
2427{
2428 if ( ! b )
2429 return;
2430
2431 b->yy_n_chars = 0;
2432
2433 /* We always need two end-of-buffer characters. The first causes
2434 * a transition to the end-of-buffer state. The second causes
2435 * a jam in that state.
2436 */
2437 b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
2438 b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
2439
2440 b->yy_buf_pos = &b->yy_ch_buf[0];
2441
2442 b->yy_at_bol = 1;
2443 b->yy_buffer_status = YY_BUFFER_NEW;
2444
2445 if ( b == YY_CURRENT_BUFFER )
2446 sensors_yy_load_buffer_state( );
2447}
2448
2449/** Pushes the new state onto the stack. The new state becomes
2450 * the current state. This function will allocate the stack
2451 * if necessary.
2452 * @param new_buffer The new state.
2453 *
2454 */
2455void sensors_yypush_buffer_state (YY_BUFFER_STATE new_buffer )
2456{
2457 if (new_buffer == NULL)
2458 return;
2459
2460 sensors_yyensure_buffer_stack();
2461
2462 /* This block is copied from sensors_yy_switch_to_buffer. */
2463 if ( YY_CURRENT_BUFFER )
2464 {
2465 /* Flush out information for old buffer. */
2466 *(yy_c_buf_p) = (yy_hold_char);
2467 YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
2468 YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
2469 }
2470
2471 /* Only push if top exists. Otherwise, replace top. */
2472 if (YY_CURRENT_BUFFER)
2473 (yy_buffer_stack_top)++;
2474 YY_CURRENT_BUFFER_LVALUE = new_buffer;
2475
2476 /* copied from sensors_yy_switch_to_buffer. */
2477 sensors_yy_load_buffer_state( );
2478 (yy_did_buffer_switch_on_eof) = 1;
2479}
2480
2481/** Removes and deletes the top of the stack, if present.
2482 * The next element becomes the new top.
2483 *
2484 */
2485void sensors_yypop_buffer_state (void)
2486{
2487 if (!YY_CURRENT_BUFFER)
2488 return;
2489
2490 sensors_yy_delete_buffer(YY_CURRENT_BUFFER );
2491 YY_CURRENT_BUFFER_LVALUE = NULL;
2492 if ((yy_buffer_stack_top) > 0)
2493 --(yy_buffer_stack_top);
2494
2495 if (YY_CURRENT_BUFFER) {
2496 sensors_yy_load_buffer_state( );
2497 (yy_did_buffer_switch_on_eof) = 1;
2498 }
2499}
2500
2501/* Allocates the stack if it does not exist.
2502 * Guarantees space for at least one push.
2503 */
2504static void sensors_yyensure_buffer_stack (void)
2505{
2506 int num_to_alloc;
2507
2508 if (!(yy_buffer_stack)) {
2509
2510 /* First allocation is just for 2 elements, since we don't know if this
2511 * scanner will even need a stack. We use 2 instead of 1 to avoid an
2512 * immediate realloc on the next call.
2513 */
2514 num_to_alloc = 1;
2515 (yy_buffer_stack) = (struct yy_buffer_state**)sensors_yyalloc
2516 (num_to_alloc * sizeof(struct yy_buffer_state*)
2517 );
2518 if ( ! (yy_buffer_stack) )
2519 YY_FATAL_ERROR( "out of dynamic memory in sensors_yyensure_buffer_stack()" );
2520
2521 memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
2522
2523 (yy_buffer_stack_max) = num_to_alloc;
2524 (yy_buffer_stack_top) = 0;
2525 return;
2526 }
2527
2528 if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
2529
2530 /* Increase the buffer to prepare for a possible push. */
2531 int grow_size = 8 /* arbitrary grow size */;
2532
2533 num_to_alloc = (yy_buffer_stack_max) + grow_size;
2534 (yy_buffer_stack) = (struct yy_buffer_state**)sensors_yyrealloc
2535 ((yy_buffer_stack),
2536 num_to_alloc * sizeof(struct yy_buffer_state*)
2537 );
2538 if ( ! (yy_buffer_stack) )
2539 YY_FATAL_ERROR( "out of dynamic memory in sensors_yyensure_buffer_stack()" );
2540
2541 /* zero only the new slots.*/
2542 memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
2543 (yy_buffer_stack_max) = num_to_alloc;
2544 }
2545}
2546
2547/** Setup the input buffer state to scan directly from a user-specified character buffer.
2548 * @param base the character buffer
2549 * @param size the size in bytes of the character buffer
2550 *
2551 * @return the newly allocated buffer state object.
2552 */
2553YY_BUFFER_STATE sensors_yy_scan_buffer (char * base, yy_size_t size )
2554{
2555 YY_BUFFER_STATE b;
2556
2557 if ( size < 2 ||
2558 base[size-2] != YY_END_OF_BUFFER_CHAR ||
2559 base[size-1] != YY_END_OF_BUFFER_CHAR )
2560 /* They forgot to leave room for the EOB's. */
2561 return 0;
2562
2563 b = (YY_BUFFER_STATE) sensors_yyalloc(sizeof( struct yy_buffer_state ) );
2564 if ( ! b )
2565 YY_FATAL_ERROR( "out of dynamic memory in sensors_yy_scan_buffer()" );
2566
2567 b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
2568 b->yy_buf_pos = b->yy_ch_buf = base;
2569 b->yy_is_our_buffer = 0;
2570 b->yy_input_file = 0;
2571 b->yy_n_chars = b->yy_buf_size;
2572 b->yy_is_interactive = 0;
2573 b->yy_at_bol = 1;
2574 b->yy_fill_buffer = 0;
2575 b->yy_buffer_status = YY_BUFFER_NEW;
2576
2577 sensors_yy_switch_to_buffer(b );
2578
2579 return b;
2580}
2581
2582/** Setup the input buffer state to scan a string. The next call to sensors_yylex() will
2583 * scan from a @e copy of @a str.
2584 * @param yystr a NUL-terminated string to scan
2585 *
2586 * @return the newly allocated buffer state object.
2587 * @note If you want to scan bytes that may contain NUL values, then use
2588 * sensors_yy_scan_bytes() instead.
2589 */
2590YY_BUFFER_STATE sensors_yy_scan_string (yyconst char * yystr )
2591{
2592
2593 return sensors_yy_scan_bytes(yystr,strlen(yystr) );
2594}
2595
2596/** Setup the input buffer state to scan the given bytes. The next call to sensors_yylex() will
2597 * scan from a @e copy of @a bytes.
2598 * @param yybytes the byte buffer to scan
2599 * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
2600 *
2601 * @return the newly allocated buffer state object.
2602 */
2603YY_BUFFER_STATE sensors_yy_scan_bytes (yyconst char * yybytes, int _yybytes_len )
2604{
2605 YY_BUFFER_STATE b;
2606 char *buf;
2607 yy_size_t n;
2608 int i;
2609
2610 /* Get memory for full buffer, including space for trailing EOB's. */
2611 n = _yybytes_len + 2;
2612 buf = (char *) sensors_yyalloc(n );
2613 if ( ! buf )
2614 YY_FATAL_ERROR( "out of dynamic memory in sensors_yy_scan_bytes()" );
2615
2616 for ( i = 0; i < _yybytes_len; ++i )
2617 buf[i] = yybytes[i];
2618
2619 buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
2620
2621 b = sensors_yy_scan_buffer(buf,n );
2622 if ( ! b )
2623 YY_FATAL_ERROR( "bad buffer in sensors_yy_scan_bytes()" );
2624
2625 /* It's okay to grow etc. this buffer, and we should throw it
2626 * away when we're done.
2627 */
2628 b->yy_is_our_buffer = 1;
2629
2630 return b;
2631}
2632
2633#ifndef YY_EXIT_FAILURE
2634#define YY_EXIT_FAILURE 2
2635#endif
2636
2637static void yy_fatal_error (yyconst char* msg )
2638{
2639 (void) fprintf( stderr, "%s\n", msg );
2640 exit( YY_EXIT_FAILURE );
2641}
2642
2643/* Redefine yyless() so it works in section 3 code. */
2644
2645#undef yyless
2646#define yyless(n) \
2647 do \
2648 { \
2649 /* Undo effects of setting up sensors_yytext. */ \
2650 int yyless_macro_arg = (n); \
2651 YY_LESS_LINENO(yyless_macro_arg);\
2652 sensors_yytext[sensors_yyleng] = (yy_hold_char); \
2653 (yy_c_buf_p) = sensors_yytext + yyless_macro_arg; \
2654 (yy_hold_char) = *(yy_c_buf_p); \
2655 *(yy_c_buf_p) = '\0'; \
2656 sensors_yyleng = yyless_macro_arg; \
2657 } \
2658 while ( 0 )
2659
2660/* Accessor methods (get/set functions) to struct members. */
2661
2662/** Get the current line number.
2663 *
2664 */
2665int sensors_yyget_lineno (void)
2666{
2667
2668 return sensors_yylineno;
2669}
2670
2671/** Get the input stream.
2672 *
2673 */
2674FILE *sensors_yyget_in (void)
2675{
2676 return sensors_yyin;
2677}
2678
2679/** Get the output stream.
2680 *
2681 */
2682FILE *sensors_yyget_out (void)
2683{
2684 return sensors_yyout;
2685}
2686
2687/** Get the length of the current token.
2688 *
2689 */
2690int sensors_yyget_leng (void)
2691{
2692 return sensors_yyleng;
2693}
2694
2695/** Get the current token.
2696 *
2697 */
2698
2699char *sensors_yyget_text (void)
2700{
2701 return sensors_yytext;
2702}
2703
2704/** Set the current line number.
2705 * @param line_number
2706 *
2707 */
2708void sensors_yyset_lineno (int line_number )
2709{
2710
2711 sensors_yylineno = line_number;
2712}
2713
2714/** Set the input stream. This does not discard the current
2715 * input buffer.
2716 * @param in_str A readable stream.
2717 *
2718 * @see sensors_yy_switch_to_buffer
2719 */
2720void sensors_yyset_in (FILE * in_str )
2721{
2722 sensors_yyin = in_str ;
2723}
2724
2725void sensors_yyset_out (FILE * out_str )
2726{
2727 sensors_yyout = out_str ;
2728}
2729
2730int sensors_yyget_debug (void)
2731{
2732 return sensors_yy_flex_debug;
2733}
2734
2735void sensors_yyset_debug (int bdebug )
2736{
2737 sensors_yy_flex_debug = bdebug ;
2738}
2739
2740static int yy_init_globals (void)
2741{
2742 /* Initialization is the same as for the non-reentrant scanner.
2743 * This function is called from sensors_yylex_destroy(), so don't allocate here.
2744 */
2745
2746 (yy_buffer_stack) = 0;
2747 (yy_buffer_stack_top) = 0;
2748 (yy_buffer_stack_max) = 0;
2749 (yy_c_buf_p) = (char *) 0;
2750 (yy_init) = 0;
2751 (yy_start) = 0;
2752
2753/* Defined in main.c */
2754#ifdef YY_STDINIT
2755 sensors_yyin = stdin;
2756 sensors_yyout = stdout;
2757#else
2758 sensors_yyin = (FILE *) 0;
2759 sensors_yyout = (FILE *) 0;
2760#endif
2761
2762 /* For future reference: Set errno on error, since we are called by
2763 * sensors_yylex_init()
2764 */
2765 return 0;
2766}
2767
2768/* sensors_yylex_destroy is for both reentrant and non-reentrant scanners. */
2769int sensors_yylex_destroy (void)
2770{
2771
2772 /* Pop the buffer stack, destroying each element. */
2773 while(YY_CURRENT_BUFFER){
2774 sensors_yy_delete_buffer(YY_CURRENT_BUFFER );
2775 YY_CURRENT_BUFFER_LVALUE = NULL;
2776 sensors_yypop_buffer_state();
2777 }
2778
2779 /* Destroy the stack itself. */
2780 sensors_yyfree((yy_buffer_stack) );
2781 (yy_buffer_stack) = NULL;
2782
2783 /* Reset the globals. This is important in a non-reentrant scanner so the next time
2784 * sensors_yylex() is called, initialization will occur. */
2785 yy_init_globals( );
2786
2787 return 0;
2788}
2789
2790/*
2791 * Internal utility routines.
2792 */
2793
2794#ifndef yytext_ptr
2795static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
2796{
2797 register int i;
2798 for ( i = 0; i < n; ++i )
2799 s1[i] = s2[i];
2800}
2801#endif
2802
2803#ifdef YY_NEED_STRLEN
2804static int yy_flex_strlen (yyconst char * s )
2805{
2806 register int n;
2807 for ( n = 0; s[n]; ++n )
2808 ;
2809
2810 return n;
2811}
2812#endif
2813
2814void *sensors_yyalloc (yy_size_t size )
2815{
2816 return (void *) malloc( size );
2817}
2818
2819void *sensors_yyrealloc (void * ptr, yy_size_t size )
2820{
2821 /* The cast to (char *) in the following accommodates both
2822 * implementations that use char* generic pointers, and those
2823 * that use void* generic pointers. It works with the latter
2824 * because both ANSI C and C++ allow castless assignment from
2825 * any pointer type to void*, and deal with argument conversions
2826 * as though doing an assignment.
2827 */
2828 return (void *) realloc( (char *) ptr, size );
2829}
2830
2831void sensors_yyfree (void * ptr )
2832{
2833 free( (char *) ptr ); /* see sensors_yyrealloc() for (char *) cast */
2834}
2835
2836#define YYTABLES_NAME "yytables"
2837
2838#line 332 "lib/conf-lex.l"
2839
2840
2841
2842/*
2843 Do the buffer handling manually. This allows us to scan as many
2844 config files as we need to, while cleaning up properly after each
2845 one. The "BEGIN(0)" line ensures that we start in the default state,
2846 even if e.g. the previous config file was syntactically broken.
2847
2848 Returns 0 if successful, !0 otherwise.
2849*/
2850
2851static YY_BUFFER_STATE scan_buf = (YY_BUFFER_STATE)0;
2852
2853int sensors_scanner_init(FILE *input, const char *filename)
2854{
2855 BEGIN(0);
2856 if (!(scan_buf = sensors_yy_create_buffer(input, YY_BUF_SIZE)))
2857 return -1;
2858
2859 sensors_yy_switch_to_buffer(scan_buf);
2860 sensors_yyfilename = filename;
2861 sensors_yylineno = 1;
2862 return 0;
2863}
2864
2865void sensors_scanner_exit(void)
2866{
2867 sensors_yy_delete_buffer(scan_buf);
2868 scan_buf = (YY_BUFFER_STATE)0;
2869
2870/* As of flex 2.5.9, sensors_yylex_destroy() must be called when done with the
2871 scaller, otherwise we'll leak memory. */
2872#if defined(YY_FLEX_MAJOR_VERSION) && defined(YY_FLEX_MINOR_VERSION) && defined(YY_FLEX_SUBMINOR_VERSION)
2873#if YY_FLEX_MAJOR_VERSION > 2 || \
2874 (YY_FLEX_MAJOR_VERSION == 2 && (YY_FLEX_MINOR_VERSION > 5 || \
2875 (YY_FLEX_MINOR_VERSION == 5 && YY_FLEX_SUBMINOR_VERSION >= 9)))
2876 sensors_yylex_destroy();
2877#endif
2878#endif
2879}
2880
2881
diff --git a/tools/gator/daemon/libsensors/conf-lex.l b/tools/gator/daemon/libsensors/conf-lex.l
new file mode 100644
index 00000000000..43ddbd8f5bd
--- /dev/null
+++ b/tools/gator/daemon/libsensors/conf-lex.l
@@ -0,0 +1,372 @@
1%{
2/*
3 conf-lex.l - Part of libsensors, a Linux library for reading sensor data.
4 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301 USA.
20*/
21
22#include <stdlib.h>
23#include <string.h>
24
25#include "general.h"
26#include "data.h"
27#include "conf-parse.h"
28#include "error.h"
29#include "scanner.h"
30
31static int buffer_count;
32static int buffer_max;
33static char *buffer;
34
35char sensors_lex_error[100];
36
37const char *sensors_yyfilename;
38int sensors_yylineno;
39
40#define buffer_malloc() sensors_malloc_array(&buffer,&buffer_count,\
41 &buffer_max,1)
42#define buffer_free() sensors_free_array(&buffer,&buffer_count,\
43 &buffer_max)
44#define buffer_add_char(c) sensors_add_array_el(c,&buffer,\
45 &buffer_count,\
46 &buffer_max,1)
47#define buffer_add_string(s) sensors_add_array_els(s,strlen(s),\
48 &buffer, \
49 &buffer_count,&buffer_max,1)
50
51%}
52
53 /* Scanner for configuration files */
54
55%option nodefault
56%option noyywrap
57%option nounput
58
59 /* All states are exclusive */
60
61%x MIDDLE
62%x STRING
63%x ERR
64
65 /* Any whitespace-like character */
66
67BLANK [ \f\r\t\v]
68
69IDCHAR [[:alnum:]_]
70
71 /* Note: `10', `10.4' and `.4' are valid, `10.' is not */
72
73FLOAT [[:digit:]]*\.?[[:digit:]]+
74
75 /* Only positive whole numbers are recognized here */
76
77NUM 0|([1-9][[:digit:]]*)
78
79
80%%
81
82 /*
83 * STATE: INITIAL
84 */
85
86<INITIAL>{
87
88<<EOF>> { /* EOF from this state terminates */
89 return 0;
90 }
91
92{BLANK}+ ; /* eat as many blanks as possible at once */
93
94{BLANK}*\n { /* eat a bare newline (possibly preceded by blanks) */
95 sensors_yylineno++;
96 }
97
98 /* comments */
99
100#.* ; /* eat the rest of the line after comment char */
101
102#.*\n { /* eat the rest of the line after comment char */
103 sensors_yylineno++;
104 }
105
106 /*
107 * Keywords must be followed by whitespace - eat that too.
108 * If there isn't trailing whitespace, we still need to
109 * accept it as lexically correct (even though the parser
110 * will reject it anyway.)
111 */
112
113label{BLANK}* {
114 sensors_yylval.line.filename = sensors_yyfilename;
115 sensors_yylval.line.lineno = sensors_yylineno;
116 BEGIN(MIDDLE);
117 return LABEL;
118 }
119
120set{BLANK}* {
121 sensors_yylval.line.filename = sensors_yyfilename;
122 sensors_yylval.line.lineno = sensors_yylineno;
123 BEGIN(MIDDLE);
124 return SET;
125 }
126
127compute{BLANK}* {
128 sensors_yylval.line.filename = sensors_yyfilename;
129 sensors_yylval.line.lineno = sensors_yylineno;
130 BEGIN(MIDDLE);
131 return COMPUTE;
132 }
133
134bus{BLANK}* {
135 sensors_yylval.line.filename = sensors_yyfilename;
136 sensors_yylval.line.lineno = sensors_yylineno;
137 BEGIN(MIDDLE);
138 return BUS;
139 }
140
141chip{BLANK}* {
142 sensors_yylval.line.filename = sensors_yyfilename;
143 sensors_yylval.line.lineno = sensors_yylineno;
144 BEGIN(MIDDLE);
145 return CHIP;
146 }
147
148ignore{BLANK}* {
149 sensors_yylval.line.filename = sensors_yyfilename;
150 sensors_yylval.line.lineno = sensors_yylineno;
151 BEGIN(MIDDLE);
152 return IGNORE;
153 }
154
155 /* Anything else at the beginning of a line is an error */
156
157[a-z]+ |
158. {
159 BEGIN(ERR);
160 strcpy(sensors_lex_error,"Invalid keyword");
161 return ERROR;
162 }
163}
164
165 /*
166 * STATE: ERROR
167 */
168
169<ERR>{
170
171.* ; /* eat whatever is left on this line */
172
173\n {
174 BEGIN(INITIAL);
175 sensors_yylineno++;
176 return EOL;
177 }
178}
179
180 /*
181 * STATE: MIDDLE
182 */
183
184<MIDDLE>{
185
186{BLANK}+ ; /* eat as many blanks as possible at once */
187
188\n { /* newline here sends EOL token to parser */
189 BEGIN(INITIAL);
190 sensors_yylineno++;
191 return EOL;
192 }
193
194<<EOF>> { /* EOF here sends EOL token to parser also */
195 BEGIN(INITIAL);
196 return EOL;
197 }
198
199\\{BLANK}*\n { /* eat an escaped newline with no state change */
200 sensors_yylineno++;
201 }
202
203 /* comments */
204
205#.* ; /* eat the rest of the line after comment char */
206
207#.*\n { /* eat the rest of the line after comment char */
208 BEGIN(INITIAL);
209 sensors_yylineno++;
210 return EOL;
211 }
212
213 /* A number */
214
215{FLOAT} {
216 sensors_yylval.value = atof(sensors_yytext);
217 return FLOAT;
218 }
219
220 /* Some operators */
221
222"+" return '+';
223"-" return '-';
224"*" return '*';
225"/" return '/';
226"(" return '(';
227")" return ')';
228"," return ',';
229"@" return '@';
230"^" return '^';
231"`" return '`';
232
233 /* Quoted string */
234
235\" {
236 buffer_malloc();
237 BEGIN(STRING);
238 }
239
240 /* A normal, unquoted identifier */
241
242{IDCHAR}+ {
243 sensors_yylval.name = strdup(sensors_yytext);
244 if (! sensors_yylval.name)
245 sensors_fatal_error("conf-lex.l",
246 "Allocating a new string");
247
248 return NAME;
249 }
250
251 /* anything else is bogus */
252
253. |
254[[:digit:]]*\. |
255\\{BLANK}* {
256 BEGIN(ERR);
257 return ERROR;
258 }
259}
260
261 /*
262 * STATE: STRING
263 */
264
265<STRING>{
266
267 /* Oops, newline or EOF while in a string is not good */
268
269\n |
270\\\n {
271 buffer_add_char("\0");
272 strcpy(sensors_lex_error,
273 "No matching double quote.");
274 buffer_free();
275 yyless(0);
276 BEGIN(ERR);
277 return ERROR;
278 }
279
280<<EOF>> {
281 strcpy(sensors_lex_error,
282 "Reached end-of-file without a matching double quote.");
283 buffer_free();
284 BEGIN(MIDDLE);
285 return ERROR;
286 }
287
288 /* At the end */
289
290\"\" {
291 buffer_add_char("\0");
292 strcpy(sensors_lex_error,
293 "Quoted strings must be separated by whitespace.");
294 buffer_free();
295 BEGIN(ERR);
296 return ERROR;
297 }
298
299\" {
300 buffer_add_char("\0");
301 sensors_yylval.name = strdup(buffer);
302 if (! sensors_yylval.name)
303 sensors_fatal_error("conf-lex.l",
304 "Allocating a new string");
305 buffer_free();
306 BEGIN(MIDDLE);
307 return NAME;
308 }
309
310\\a buffer_add_char("\a");
311\\b buffer_add_char("\b");
312\\f buffer_add_char("\f");
313\\n buffer_add_char("\n");
314\\r buffer_add_char("\r");
315\\t buffer_add_char("\t");
316\\v buffer_add_char("\v");
317
318 /* Other escapes: just copy the character behind the slash */
319
320\\. {
321 buffer_add_char(&sensors_yytext[1]);
322 }
323
324 /* Anything else (including a bare '\' which may be followed by EOF) */
325
326\\ |
327[^\\\n\"]+ {
328 buffer_add_string(sensors_yytext);
329 }
330}
331
332%%
333
334/*
335 Do the buffer handling manually. This allows us to scan as many
336 config files as we need to, while cleaning up properly after each
337 one. The "BEGIN(0)" line ensures that we start in the default state,
338 even if e.g. the previous config file was syntactically broken.
339
340 Returns 0 if successful, !0 otherwise.
341*/
342
343static YY_BUFFER_STATE scan_buf = (YY_BUFFER_STATE)0;
344
345int sensors_scanner_init(FILE *input, const char *filename)
346{
347 BEGIN(0);
348 if (!(scan_buf = sensors_yy_create_buffer(input, YY_BUF_SIZE)))
349 return -1;
350
351 sensors_yy_switch_to_buffer(scan_buf);
352 sensors_yyfilename = filename;
353 sensors_yylineno = 1;
354 return 0;
355}
356
357void sensors_scanner_exit(void)
358{
359 sensors_yy_delete_buffer(scan_buf);
360 scan_buf = (YY_BUFFER_STATE)0;
361
362/* As of flex 2.5.9, yylex_destroy() must be called when done with the
363 scaller, otherwise we'll leak memory. */
364#if defined(YY_FLEX_MAJOR_VERSION) && defined(YY_FLEX_MINOR_VERSION) && defined(YY_FLEX_SUBMINOR_VERSION)
365#if YY_FLEX_MAJOR_VERSION > 2 || \
366 (YY_FLEX_MAJOR_VERSION == 2 && (YY_FLEX_MINOR_VERSION > 5 || \
367 (YY_FLEX_MINOR_VERSION == 5 && YY_FLEX_SUBMINOR_VERSION >= 9)))
368 sensors_yylex_destroy();
369#endif
370#endif
371}
372
diff --git a/tools/gator/daemon/libsensors/conf-parse.c b/tools/gator/daemon/libsensors/conf-parse.c
new file mode 100644
index 00000000000..fb775460a1c
--- /dev/null
+++ b/tools/gator/daemon/libsensors/conf-parse.c
@@ -0,0 +1,2042 @@
1/* A Bison parser, made by GNU Bison 2.5. */
2
3/* Bison implementation for Yacc-like parsers in C
4
5 Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
6
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19
20/* As a special exception, you may create a larger work that contains
21 part or all of the Bison parser skeleton and distribute that work
22 under terms of your choice, so long as that work isn't itself a
23 parser generator using the skeleton or a modified version thereof
24 as a parser skeleton. Alternatively, if you modify or redistribute
25 the parser skeleton itself, you may (at your option) remove this
26 special exception, which will cause the skeleton and the resulting
27 Bison output files to be licensed under the GNU General Public
28 License without this special exception.
29
30 This special exception was added by the Free Software Foundation in
31 version 2.2 of Bison. */
32
33/* C LALR(1) parser skeleton written by Richard Stallman, by
34 simplifying the original so-called "semantic" parser. */
35
36/* All symbols defined below should begin with yy or YY, to avoid
37 infringing on user name space. This should be done even for local
38 variables, as they might otherwise be expanded by user macros.
39 There are some unavoidable exceptions within include files to
40 define necessary library symbols; they are noted "INFRINGES ON
41 USER NAME SPACE" below. */
42
43/* Identify Bison output. */
44#define YYBISON 1
45
46/* Bison version. */
47#define YYBISON_VERSION "2.5"
48
49/* Skeleton name. */
50#define YYSKELETON_NAME "yacc.c"
51
52/* Pure parsers. */
53#define YYPURE 0
54
55/* Push parsers. */
56#define YYPUSH 0
57
58/* Pull parsers. */
59#define YYPULL 1
60
61/* Using locations. */
62#define YYLSP_NEEDED 0
63
64/* Substitute the variable and function names. */
65#define yyparse sensors_yyparse
66#define yylex sensors_yylex
67#define yyerror sensors_yyerror
68#define yylval sensors_yylval
69#define yychar sensors_yychar
70#define yydebug sensors_yydebug
71#define yynerrs sensors_yynerrs
72
73
74/* Copy the first part of user declarations. */
75
76/* Line 268 of yacc.c */
77#line 1 "lib/conf-parse.y"
78
79/*
80 conf-parse.y - Part of libsensors, a Linux library for reading sensor data.
81 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
82
83 This library is free software; you can redistribute it and/or
84 modify it under the terms of the GNU Lesser General Public
85 License as published by the Free Software Foundation; either
86 version 2.1 of the License, or (at your option) any later version.
87
88 This library is distributed in the hope that it will be useful,
89 but WITHOUT ANY WARRANTY; without even the implied warranty of
90 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
91 GNU Lesser General Public License for more details.
92
93 You should have received a copy of the GNU General Public License
94 along with this program; if not, write to the Free Software
95 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
96 MA 02110-1301 USA.
97*/
98
99#define YYERROR_VERBOSE
100
101#include <stdio.h>
102#include <string.h>
103#include <stdlib.h>
104
105#include "data.h"
106#include "general.h"
107#include "error.h"
108#include "conf.h"
109#include "access.h"
110#include "init.h"
111
112static void sensors_yyerror(const char *err);
113static sensors_expr *malloc_expr(void);
114
115static sensors_chip *current_chip = NULL;
116
117#define bus_add_el(el) sensors_add_array_el(el,\
118 &sensors_config_busses,\
119 &sensors_config_busses_count,\
120 &sensors_config_busses_max,\
121 sizeof(sensors_bus))
122#define label_add_el(el) sensors_add_array_el(el,\
123 &current_chip->labels,\
124 &current_chip->labels_count,\
125 &current_chip->labels_max,\
126 sizeof(sensors_label));
127#define set_add_el(el) sensors_add_array_el(el,\
128 &current_chip->sets,\
129 &current_chip->sets_count,\
130 &current_chip->sets_max,\
131 sizeof(sensors_set));
132#define compute_add_el(el) sensors_add_array_el(el,\
133 &current_chip->computes,\
134 &current_chip->computes_count,\
135 &current_chip->computes_max,\
136 sizeof(sensors_compute));
137#define ignore_add_el(el) sensors_add_array_el(el,\
138 &current_chip->ignores,\
139 &current_chip->ignores_count,\
140 &current_chip->ignores_max,\
141 sizeof(sensors_ignore));
142#define chip_add_el(el) sensors_add_array_el(el,\
143 &sensors_config_chips,\
144 &sensors_config_chips_count,\
145 &sensors_config_chips_max,\
146 sizeof(sensors_chip));
147
148#define fits_add_el(el,list) sensors_add_array_el(el,\
149 &(list).fits,\
150 &(list).fits_count,\
151 &(list).fits_max, \
152 sizeof(sensors_chip_name));
153
154
155
156/* Line 268 of yacc.c */
157#line 158 "lib/conf-parse.c"
158
159/* Enabling traces. */
160#ifndef YYDEBUG
161# define YYDEBUG 0
162#endif
163
164/* Enabling verbose error messages. */
165#ifdef YYERROR_VERBOSE
166# undef YYERROR_VERBOSE
167# define YYERROR_VERBOSE 1
168#else
169# define YYERROR_VERBOSE 0
170#endif
171
172/* Enabling the token table. */
173#ifndef YYTOKEN_TABLE
174# define YYTOKEN_TABLE 0
175#endif
176
177
178/* Tokens. */
179#ifndef YYTOKENTYPE
180# define YYTOKENTYPE
181 /* Put the tokens into the symbol table, so that GDB and other debuggers
182 know about them. */
183 enum yytokentype {
184 NEG = 258,
185 EOL = 259,
186 BUS = 260,
187 LABEL = 261,
188 SET = 262,
189 CHIP = 263,
190 COMPUTE = 264,
191 IGNORE = 265,
192 FLOAT = 266,
193 NAME = 267,
194 ERROR = 268
195 };
196#endif
197
198
199
200#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
201typedef union YYSTYPE
202{
203
204/* Line 293 of yacc.c */
205#line 79 "lib/conf-parse.y"
206
207 double value;
208 char *name;
209 void *nothing;
210 sensors_chip_name_list chips;
211 sensors_expr *expr;
212 sensors_bus_id bus;
213 sensors_chip_name chip;
214 sensors_config_line line;
215
216
217
218/* Line 293 of yacc.c */
219#line 220 "lib/conf-parse.c"
220} YYSTYPE;
221# define YYSTYPE_IS_TRIVIAL 1
222# define yystype YYSTYPE /* obsolescent; will be withdrawn */
223# define YYSTYPE_IS_DECLARED 1
224#endif
225
226
227/* Copy the second part of user declarations. */
228
229
230/* Line 343 of yacc.c */
231#line 232 "lib/conf-parse.c"
232
233#ifdef short
234# undef short
235#endif
236
237#ifdef YYTYPE_UINT8
238typedef YYTYPE_UINT8 yytype_uint8;
239#else
240typedef unsigned char yytype_uint8;
241#endif
242
243#ifdef YYTYPE_INT8
244typedef YYTYPE_INT8 yytype_int8;
245#elif (defined __STDC__ || defined __C99__FUNC__ \
246 || defined __cplusplus || defined _MSC_VER)
247typedef signed char yytype_int8;
248#else
249typedef short int yytype_int8;
250#endif
251
252#ifdef YYTYPE_UINT16
253typedef YYTYPE_UINT16 yytype_uint16;
254#else
255typedef unsigned short int yytype_uint16;
256#endif
257
258#ifdef YYTYPE_INT16
259typedef YYTYPE_INT16 yytype_int16;
260#else
261typedef short int yytype_int16;
262#endif
263
264#ifndef YYSIZE_T
265# ifdef __SIZE_TYPE__
266# define YYSIZE_T __SIZE_TYPE__
267# elif defined size_t
268# define YYSIZE_T size_t
269# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
270 || defined __cplusplus || defined _MSC_VER)
271# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
272# define YYSIZE_T size_t
273# else
274# define YYSIZE_T unsigned int
275# endif
276#endif
277
278#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
279
280#ifndef YY_
281# if defined YYENABLE_NLS && YYENABLE_NLS
282# if ENABLE_NLS
283# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
284# define YY_(msgid) dgettext ("bison-runtime", msgid)
285# endif
286# endif
287# ifndef YY_
288# define YY_(msgid) msgid
289# endif
290#endif
291
292/* Suppress unused-variable warnings by "using" E. */
293#if ! defined lint || defined __GNUC__
294# define YYUSE(e) ((void) (e))
295#else
296# define YYUSE(e) /* empty */
297#endif
298
299/* Identity function, used to suppress warnings about constant conditions. */
300#ifndef lint
301# define YYID(n) (n)
302#else
303#if (defined __STDC__ || defined __C99__FUNC__ \
304 || defined __cplusplus || defined _MSC_VER)
305static int
306YYID (int yyi)
307#else
308static int
309YYID (yyi)
310 int yyi;
311#endif
312{
313 return yyi;
314}
315#endif
316
317#if ! defined yyoverflow || YYERROR_VERBOSE
318
319/* The parser invokes alloca or malloc; define the necessary symbols. */
320
321# ifdef YYSTACK_USE_ALLOCA
322# if YYSTACK_USE_ALLOCA
323# ifdef __GNUC__
324# define YYSTACK_ALLOC __builtin_alloca
325# elif defined __BUILTIN_VA_ARG_INCR
326# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
327# elif defined _AIX
328# define YYSTACK_ALLOC __alloca
329# elif defined _MSC_VER
330# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
331# define alloca _alloca
332# else
333# define YYSTACK_ALLOC alloca
334# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
335 || defined __cplusplus || defined _MSC_VER)
336# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
337# ifndef EXIT_SUCCESS
338# define EXIT_SUCCESS 0
339# endif
340# endif
341# endif
342# endif
343# endif
344
345# ifdef YYSTACK_ALLOC
346 /* Pacify GCC's `empty if-body' warning. */
347# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
348# ifndef YYSTACK_ALLOC_MAXIMUM
349 /* The OS might guarantee only one guard page at the bottom of the stack,
350 and a page size can be as small as 4096 bytes. So we cannot safely
351 invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
352 to allow for a few compiler-allocated temporary stack slots. */
353# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
354# endif
355# else
356# define YYSTACK_ALLOC YYMALLOC
357# define YYSTACK_FREE YYFREE
358# ifndef YYSTACK_ALLOC_MAXIMUM
359# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
360# endif
361# if (defined __cplusplus && ! defined EXIT_SUCCESS \
362 && ! ((defined YYMALLOC || defined malloc) \
363 && (defined YYFREE || defined free)))
364# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
365# ifndef EXIT_SUCCESS
366# define EXIT_SUCCESS 0
367# endif
368# endif
369# ifndef YYMALLOC
370# define YYMALLOC malloc
371# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
372 || defined __cplusplus || defined _MSC_VER)
373void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
374# endif
375# endif
376# ifndef YYFREE
377# define YYFREE free
378# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
379 || defined __cplusplus || defined _MSC_VER)
380void free (void *); /* INFRINGES ON USER NAME SPACE */
381# endif
382# endif
383# endif
384#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
385
386
387#if (! defined yyoverflow \
388 && (! defined __cplusplus \
389 || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
390
391/* A type that is properly aligned for any stack member. */
392union yyalloc
393{
394 yytype_int16 yyss_alloc;
395 YYSTYPE yyvs_alloc;
396};
397
398/* The size of the maximum gap between one aligned stack and the next. */
399# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
400
401/* The size of an array large to enough to hold all stacks, each with
402 N elements. */
403# define YYSTACK_BYTES(N) \
404 ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
405 + YYSTACK_GAP_MAXIMUM)
406
407# define YYCOPY_NEEDED 1
408
409/* Relocate STACK from its old location to the new one. The
410 local variables YYSIZE and YYSTACKSIZE give the old and new number of
411 elements in the stack, and YYPTR gives the new location of the
412 stack. Advance YYPTR to a properly aligned location for the next
413 stack. */
414# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
415 do \
416 { \
417 YYSIZE_T yynewbytes; \
418 YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
419 Stack = &yyptr->Stack_alloc; \
420 yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
421 yyptr += yynewbytes / sizeof (*yyptr); \
422 } \
423 while (YYID (0))
424
425#endif
426
427#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
428/* Copy COUNT objects from FROM to TO. The source and destination do
429 not overlap. */
430# ifndef YYCOPY
431# if defined __GNUC__ && 1 < __GNUC__
432# define YYCOPY(To, From, Count) \
433 __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
434# else
435# define YYCOPY(To, From, Count) \
436 do \
437 { \
438 YYSIZE_T yyi; \
439 for (yyi = 0; yyi < (Count); yyi++) \
440 (To)[yyi] = (From)[yyi]; \
441 } \
442 while (YYID (0))
443# endif
444# endif
445#endif /* !YYCOPY_NEEDED */
446
447/* YYFINAL -- State number of the termination state. */
448#define YYFINAL 2
449/* YYLAST -- Last index in YYTABLE. */
450#define YYLAST 58
451
452/* YYNTOKENS -- Number of terminals. */
453#define YYNTOKENS 24
454/* YYNNTS -- Number of nonterminals. */
455#define YYNNTS 16
456/* YYNRULES -- Number of rules. */
457#define YYNRULES 34
458/* YYNRULES -- Number of states. */
459#define YYNSTATES 63
460
461/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
462#define YYUNDEFTOK 2
463#define YYMAXUTOK 268
464
465#define YYTRANSLATE(YYX) \
466 ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
467
468/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
469static const yytype_uint8 yytranslate[] =
470{
471 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
472 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
473 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
474 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
475 22, 23, 5, 4, 10, 3, 2, 6, 2, 2,
476 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
477 2, 2, 2, 2, 21, 2, 2, 2, 2, 2,
478 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
479 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
480 2, 2, 2, 2, 8, 2, 9, 2, 2, 2,
481 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
482 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
483 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
484 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
485 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
486 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
487 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
488 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
489 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
490 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
491 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
492 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
493 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
494 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
495 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
496 2, 2, 2, 2, 2, 2, 1, 2, 7, 11,
497 12, 13, 14, 15, 16, 17, 18, 19, 20
498};
499
500#if YYDEBUG
501/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
502 YYRHS. */
503static const yytype_uint8 yyprhs[] =
504{
505 0, 0, 3, 4, 7, 10, 13, 16, 19, 22,
506 25, 28, 32, 36, 40, 46, 49, 52, 54, 57,
507 59, 61, 63, 67, 71, 75, 79, 82, 86, 89,
508 92, 94, 96, 98, 100
509};
510
511/* YYRHS -- A `-1'-separated list of the rules' RHS. */
512static const yytype_int8 yyrhs[] =
513{
514 25, 0, -1, -1, 25, 26, -1, 27, 11, -1,
515 28, 11, -1, 29, 11, -1, 32, 11, -1, 30,
516 11, -1, 31, 11, -1, 1, 11, -1, 12, 35,
517 36, -1, 13, 37, 38, -1, 14, 37, 34, -1,
518 16, 37, 34, 10, 34, -1, 17, 37, -1, 15,
519 33, -1, 39, -1, 33, 39, -1, 18, -1, 19,
520 -1, 21, -1, 34, 4, 34, -1, 34, 3, 34,
521 -1, 34, 5, 34, -1, 34, 6, 34, -1, 3,
522 34, -1, 22, 34, 23, -1, 8, 34, -1, 9,
523 34, -1, 19, -1, 19, -1, 19, -1, 19, -1,
524 19, -1
525};
526
527/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
528static const yytype_uint16 yyrline[] =
529{
530 0, 119, 119, 120, 123, 124, 125, 126, 127, 128,
531 129, 132, 141, 156, 171, 188, 201, 219, 225, 231,
532 236, 241, 245, 252, 259, 266, 273, 280, 282, 289,
533 298, 308, 312, 316, 320
534};
535#endif
536
537#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
538/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
539 First, the terminals, then, starting at YYNTOKENS, nonterminals. */
540static const char *const yytname[] =
541{
542 "$end", "error", "$undefined", "'-'", "'+'", "'*'", "'/'", "NEG", "'^'",
543 "'`'", "','", "EOL", "BUS", "LABEL", "SET", "CHIP", "COMPUTE", "IGNORE",
544 "FLOAT", "NAME", "ERROR", "'@'", "'('", "')'", "$accept", "input",
545 "line", "bus_statement", "label_statement", "set_statement",
546 "compute_statement", "ignore_statement", "chip_statement",
547 "chip_name_list", "expression", "bus_id", "adapter_name",
548 "function_name", "string", "chip_name", 0
549};
550#endif
551
552# ifdef YYPRINT
553/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
554 token YYLEX-NUM. */
555static const yytype_uint16 yytoknum[] =
556{
557 0, 256, 257, 45, 43, 42, 47, 258, 94, 96,
558 44, 259, 260, 261, 262, 263, 264, 265, 266, 267,
559 268, 64, 40, 41
560};
561# endif
562
563/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
564static const yytype_uint8 yyr1[] =
565{
566 0, 24, 25, 25, 26, 26, 26, 26, 26, 26,
567 26, 27, 28, 29, 30, 31, 32, 33, 33, 34,
568 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
569 35, 36, 37, 38, 39
570};
571
572/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
573static const yytype_uint8 yyr2[] =
574{
575 0, 2, 0, 2, 2, 2, 2, 2, 2, 2,
576 2, 3, 3, 3, 5, 2, 2, 1, 2, 1,
577 1, 1, 3, 3, 3, 3, 2, 3, 2, 2,
578 1, 1, 1, 1, 1
579};
580
581/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
582 Performed when YYTABLE doesn't specify something else to do. Zero
583 means the default is an error. */
584static const yytype_uint8 yydefact[] =
585{
586 2, 0, 1, 0, 0, 0, 0, 0, 0, 0,
587 3, 0, 0, 0, 0, 0, 0, 10, 30, 0,
588 32, 0, 0, 34, 16, 17, 0, 15, 4, 5,
589 6, 8, 9, 7, 31, 11, 33, 12, 0, 0,
590 0, 19, 20, 21, 0, 13, 18, 0, 26, 28,
591 29, 0, 0, 0, 0, 0, 0, 27, 23, 22,
592 24, 25, 14
593};
594
595/* YYDEFGOTO[NTERM-NUM]. */
596static const yytype_int8 yydefgoto[] =
597{
598 -1, 1, 10, 11, 12, 13, 14, 15, 16, 24,
599 45, 19, 35, 21, 37, 25
600};
601
602/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
603 STATE-NUM. */
604#define YYPACT_NINF -27
605static const yytype_int8 yypact[] =
606{
607 -27, 37, -27, -4, -3, 1, 1, 6, 1, 1,
608 -27, 8, 13, 20, 23, 32, 34, -27, -27, 29,
609 -27, 39, 14, -27, 6, -27, 14, -27, -27, -27,
610 -27, -27, -27, -27, -27, -27, -27, -27, 14, 14,
611 14, -27, -27, -27, 14, 36, -27, 5, -27, -27,
612 -27, -2, 14, 14, 14, 14, 14, -27, 0, 0,
613 -27, -27, 36
614};
615
616/* YYPGOTO[NTERM-NUM]. */
617static const yytype_int8 yypgoto[] =
618{
619 -27, -27, -27, -27, -27, -27, -27, -27, -27, -27,
620 -26, -27, -27, 38, -27, 31
621};
622
623/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
624 positive, shift that token. If negative, reduce the rule which
625 number is the opposite. If YYTABLE_NINF, syntax error. */
626#define YYTABLE_NINF -1
627static const yytype_uint8 yytable[] =
628{
629 47, 52, 53, 54, 55, 54, 55, 17, 52, 53,
630 54, 55, 48, 49, 50, 56, 18, 38, 51, 28,
631 20, 57, 39, 40, 29, 23, 58, 59, 60, 61,
632 62, 30, 41, 42, 31, 43, 44, 2, 3, 52,
633 53, 54, 55, 32, 22, 33, 26, 27, 34, 4,
634 5, 6, 7, 8, 9, 46, 0, 0, 36
635};
636
637#define yypact_value_is_default(yystate) \
638 ((yystate) == (-27))
639
640#define yytable_value_is_error(yytable_value) \
641 YYID (0)
642
643static const yytype_int8 yycheck[] =
644{
645 26, 3, 4, 5, 6, 5, 6, 11, 3, 4,
646 5, 6, 38, 39, 40, 10, 19, 3, 44, 11,
647 19, 23, 8, 9, 11, 19, 52, 53, 54, 55,
648 56, 11, 18, 19, 11, 21, 22, 0, 1, 3,
649 4, 5, 6, 11, 6, 11, 8, 9, 19, 12,
650 13, 14, 15, 16, 17, 24, -1, -1, 19
651};
652
653/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
654 symbol of state STATE-NUM. */
655static const yytype_uint8 yystos[] =
656{
657 0, 25, 0, 1, 12, 13, 14, 15, 16, 17,
658 26, 27, 28, 29, 30, 31, 32, 11, 19, 35,
659 19, 37, 37, 19, 33, 39, 37, 37, 11, 11,
660 11, 11, 11, 11, 19, 36, 19, 38, 3, 8,
661 9, 18, 19, 21, 22, 34, 39, 34, 34, 34,
662 34, 34, 3, 4, 5, 6, 10, 23, 34, 34,
663 34, 34, 34
664};
665
666#define yyerrok (yyerrstatus = 0)
667#define yyclearin (yychar = YYEMPTY)
668#define YYEMPTY (-2)
669#define YYEOF 0
670
671#define YYACCEPT goto yyacceptlab
672#define YYABORT goto yyabortlab
673#define YYERROR goto yyerrorlab
674
675
676/* Like YYERROR except do call yyerror. This remains here temporarily
677 to ease the transition to the new meaning of YYERROR, for GCC.
678 Once GCC version 2 has supplanted version 1, this can go. However,
679 YYFAIL appears to be in use. Nevertheless, it is formally deprecated
680 in Bison 2.4.2's NEWS entry, where a plan to phase it out is
681 discussed. */
682
683#define YYFAIL goto yyerrlab
684#if defined YYFAIL
685 /* This is here to suppress warnings from the GCC cpp's
686 -Wunused-macros. Normally we don't worry about that warning, but
687 some users do, and we want to make it easy for users to remove
688 YYFAIL uses, which will produce warnings from Bison 2.5. */
689#endif
690
691#define YYRECOVERING() (!!yyerrstatus)
692
693#define YYBACKUP(Token, Value) \
694do \
695 if (yychar == YYEMPTY && yylen == 1) \
696 { \
697 yychar = (Token); \
698 yylval = (Value); \
699 YYPOPSTACK (1); \
700 goto yybackup; \
701 } \
702 else \
703 { \
704 yyerror (YY_("syntax error: cannot back up")); \
705 YYERROR; \
706 } \
707while (YYID (0))
708
709
710#define YYTERROR 1
711#define YYERRCODE 256
712
713
714/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
715 If N is 0, then set CURRENT to the empty location which ends
716 the previous symbol: RHS[0] (always defined). */
717
718#define YYRHSLOC(Rhs, K) ((Rhs)[K])
719#ifndef YYLLOC_DEFAULT
720# define YYLLOC_DEFAULT(Current, Rhs, N) \
721 do \
722 if (YYID (N)) \
723 { \
724 (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
725 (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
726 (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
727 (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
728 } \
729 else \
730 { \
731 (Current).first_line = (Current).last_line = \
732 YYRHSLOC (Rhs, 0).last_line; \
733 (Current).first_column = (Current).last_column = \
734 YYRHSLOC (Rhs, 0).last_column; \
735 } \
736 while (YYID (0))
737#endif
738
739
740/* This macro is provided for backward compatibility. */
741
742#ifndef YY_LOCATION_PRINT
743# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
744#endif
745
746
747/* YYLEX -- calling `yylex' with the right arguments. */
748
749#ifdef YYLEX_PARAM
750# define YYLEX yylex (YYLEX_PARAM)
751#else
752# define YYLEX yylex ()
753#endif
754
755/* Enable debugging if requested. */
756#if YYDEBUG
757
758# ifndef YYFPRINTF
759# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
760# define YYFPRINTF fprintf
761# endif
762
763# define YYDPRINTF(Args) \
764do { \
765 if (yydebug) \
766 YYFPRINTF Args; \
767} while (YYID (0))
768
769# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
770do { \
771 if (yydebug) \
772 { \
773 YYFPRINTF (stderr, "%s ", Title); \
774 yy_symbol_print (stderr, \
775 Type, Value); \
776 YYFPRINTF (stderr, "\n"); \
777 } \
778} while (YYID (0))
779
780
781/*--------------------------------.
782| Print this symbol on YYOUTPUT. |
783`--------------------------------*/
784
785/*ARGSUSED*/
786#if (defined __STDC__ || defined __C99__FUNC__ \
787 || defined __cplusplus || defined _MSC_VER)
788static void
789yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
790#else
791static void
792yy_symbol_value_print (yyoutput, yytype, yyvaluep)
793 FILE *yyoutput;
794 int yytype;
795 YYSTYPE const * const yyvaluep;
796#endif
797{
798 if (!yyvaluep)
799 return;
800# ifdef YYPRINT
801 if (yytype < YYNTOKENS)
802 YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
803# else
804 YYUSE (yyoutput);
805# endif
806 switch (yytype)
807 {
808 default:
809 break;
810 }
811}
812
813
814/*--------------------------------.
815| Print this symbol on YYOUTPUT. |
816`--------------------------------*/
817
818#if (defined __STDC__ || defined __C99__FUNC__ \
819 || defined __cplusplus || defined _MSC_VER)
820static void
821yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
822#else
823static void
824yy_symbol_print (yyoutput, yytype, yyvaluep)
825 FILE *yyoutput;
826 int yytype;
827 YYSTYPE const * const yyvaluep;
828#endif
829{
830 if (yytype < YYNTOKENS)
831 YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
832 else
833 YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
834
835 yy_symbol_value_print (yyoutput, yytype, yyvaluep);
836 YYFPRINTF (yyoutput, ")");
837}
838
839/*------------------------------------------------------------------.
840| yy_stack_print -- Print the state stack from its BOTTOM up to its |
841| TOP (included). |
842`------------------------------------------------------------------*/
843
844#if (defined __STDC__ || defined __C99__FUNC__ \
845 || defined __cplusplus || defined _MSC_VER)
846static void
847yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
848#else
849static void
850yy_stack_print (yybottom, yytop)
851 yytype_int16 *yybottom;
852 yytype_int16 *yytop;
853#endif
854{
855 YYFPRINTF (stderr, "Stack now");
856 for (; yybottom <= yytop; yybottom++)
857 {
858 int yybot = *yybottom;
859 YYFPRINTF (stderr, " %d", yybot);
860 }
861 YYFPRINTF (stderr, "\n");
862}
863
864# define YY_STACK_PRINT(Bottom, Top) \
865do { \
866 if (yydebug) \
867 yy_stack_print ((Bottom), (Top)); \
868} while (YYID (0))
869
870
871/*------------------------------------------------.
872| Report that the YYRULE is going to be reduced. |
873`------------------------------------------------*/
874
875#if (defined __STDC__ || defined __C99__FUNC__ \
876 || defined __cplusplus || defined _MSC_VER)
877static void
878yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
879#else
880static void
881yy_reduce_print (yyvsp, yyrule)
882 YYSTYPE *yyvsp;
883 int yyrule;
884#endif
885{
886 int yynrhs = yyr2[yyrule];
887 int yyi;
888 unsigned long int yylno = yyrline[yyrule];
889 YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
890 yyrule - 1, yylno);
891 /* The symbols being reduced. */
892 for (yyi = 0; yyi < yynrhs; yyi++)
893 {
894 YYFPRINTF (stderr, " $%d = ", yyi + 1);
895 yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
896 &(yyvsp[(yyi + 1) - (yynrhs)])
897 );
898 YYFPRINTF (stderr, "\n");
899 }
900}
901
902# define YY_REDUCE_PRINT(Rule) \
903do { \
904 if (yydebug) \
905 yy_reduce_print (yyvsp, Rule); \
906} while (YYID (0))
907
908/* Nonzero means print parse trace. It is left uninitialized so that
909 multiple parsers can coexist. */
910int yydebug;
911#else /* !YYDEBUG */
912# define YYDPRINTF(Args)
913# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
914# define YY_STACK_PRINT(Bottom, Top)
915# define YY_REDUCE_PRINT(Rule)
916#endif /* !YYDEBUG */
917
918
919/* YYINITDEPTH -- initial size of the parser's stacks. */
920#ifndef YYINITDEPTH
921# define YYINITDEPTH 200
922#endif
923
924/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
925 if the built-in stack extension method is used).
926
927 Do not make this value too large; the results are undefined if
928 YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
929 evaluated with infinite-precision integer arithmetic. */
930
931#ifndef YYMAXDEPTH
932# define YYMAXDEPTH 10000
933#endif
934
935
936#if YYERROR_VERBOSE
937
938# ifndef yystrlen
939# if defined __GLIBC__ && defined _STRING_H
940# define yystrlen strlen
941# else
942/* Return the length of YYSTR. */
943#if (defined __STDC__ || defined __C99__FUNC__ \
944 || defined __cplusplus || defined _MSC_VER)
945static YYSIZE_T
946yystrlen (const char *yystr)
947#else
948static YYSIZE_T
949yystrlen (yystr)
950 const char *yystr;
951#endif
952{
953 YYSIZE_T yylen;
954 for (yylen = 0; yystr[yylen]; yylen++)
955 continue;
956 return yylen;
957}
958# endif
959# endif
960
961# ifndef yystpcpy
962# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
963# define yystpcpy stpcpy
964# else
965/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
966 YYDEST. */
967#if (defined __STDC__ || defined __C99__FUNC__ \
968 || defined __cplusplus || defined _MSC_VER)
969static char *
970yystpcpy (char *yydest, const char *yysrc)
971#else
972static char *
973yystpcpy (yydest, yysrc)
974 char *yydest;
975 const char *yysrc;
976#endif
977{
978 char *yyd = yydest;
979 const char *yys = yysrc;
980
981 while ((*yyd++ = *yys++) != '\0')
982 continue;
983
984 return yyd - 1;
985}
986# endif
987# endif
988
989# ifndef yytnamerr
990/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
991 quotes and backslashes, so that it's suitable for yyerror. The
992 heuristic is that double-quoting is unnecessary unless the string
993 contains an apostrophe, a comma, or backslash (other than
994 backslash-backslash). YYSTR is taken from yytname. If YYRES is
995 null, do not copy; instead, return the length of what the result
996 would have been. */
997static YYSIZE_T
998yytnamerr (char *yyres, const char *yystr)
999{
1000 if (*yystr == '"')
1001 {
1002 YYSIZE_T yyn = 0;
1003 char const *yyp = yystr;
1004
1005 for (;;)
1006 switch (*++yyp)
1007 {
1008 case '\'':
1009 case ',':
1010 goto do_not_strip_quotes;
1011
1012 case '\\':
1013 if (*++yyp != '\\')
1014 goto do_not_strip_quotes;
1015 /* Fall through. */
1016 default:
1017 if (yyres)
1018 yyres[yyn] = *yyp;
1019 yyn++;
1020 break;
1021
1022 case '"':
1023 if (yyres)
1024 yyres[yyn] = '\0';
1025 return yyn;
1026 }
1027 do_not_strip_quotes: ;
1028 }
1029
1030 if (! yyres)
1031 return yystrlen (yystr);
1032
1033 return yystpcpy (yyres, yystr) - yyres;
1034}
1035# endif
1036
1037/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
1038 about the unexpected token YYTOKEN for the state stack whose top is
1039 YYSSP.
1040
1041 Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is
1042 not large enough to hold the message. In that case, also set
1043 *YYMSG_ALLOC to the required number of bytes. Return 2 if the
1044 required number of bytes is too large to store. */
1045static int
1046yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
1047 yytype_int16 *yyssp, int yytoken)
1048{
1049 YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]);
1050 YYSIZE_T yysize = yysize0;
1051 YYSIZE_T yysize1;
1052 enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
1053 /* Internationalized format string. */
1054 const char *yyformat = 0;
1055 /* Arguments of yyformat. */
1056 char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
1057 /* Number of reported tokens (one for the "unexpected", one per
1058 "expected"). */
1059 int yycount = 0;
1060
1061 /* There are many possibilities here to consider:
1062 - Assume YYFAIL is not used. It's too flawed to consider. See
1063 <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
1064 for details. YYERROR is fine as it does not invoke this
1065 function.
1066 - If this state is a consistent state with a default action, then
1067 the only way this function was invoked is if the default action
1068 is an error action. In that case, don't check for expected
1069 tokens because there are none.
1070 - The only way there can be no lookahead present (in yychar) is if
1071 this state is a consistent state with a default action. Thus,
1072 detecting the absence of a lookahead is sufficient to determine
1073 that there is no unexpected or expected token to report. In that
1074 case, just report a simple "syntax error".
1075 - Don't assume there isn't a lookahead just because this state is a
1076 consistent state with a default action. There might have been a
1077 previous inconsistent state, consistent state with a non-default
1078 action, or user semantic action that manipulated yychar.
1079 - Of course, the expected token list depends on states to have
1080 correct lookahead information, and it depends on the parser not
1081 to perform extra reductions after fetching a lookahead from the
1082 scanner and before detecting a syntax error. Thus, state merging
1083 (from LALR or IELR) and default reductions corrupt the expected
1084 token list. However, the list is correct for canonical LR with
1085 one exception: it will still contain any token that will not be
1086 accepted due to an error action in a later state.
1087 */
1088 if (yytoken != YYEMPTY)
1089 {
1090 int yyn = yypact[*yyssp];
1091 yyarg[yycount++] = yytname[yytoken];
1092 if (!yypact_value_is_default (yyn))
1093 {
1094 /* Start YYX at -YYN if negative to avoid negative indexes in
1095 YYCHECK. In other words, skip the first -YYN actions for
1096 this state because they are default actions. */
1097 int yyxbegin = yyn < 0 ? -yyn : 0;
1098 /* Stay within bounds of both yycheck and yytname. */
1099 int yychecklim = YYLAST - yyn + 1;
1100 int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
1101 int yyx;
1102
1103 for (yyx = yyxbegin; yyx < yyxend; ++yyx)
1104 if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
1105 && !yytable_value_is_error (yytable[yyx + yyn]))
1106 {
1107 if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
1108 {
1109 yycount = 1;
1110 yysize = yysize0;
1111 break;
1112 }
1113 yyarg[yycount++] = yytname[yyx];
1114 yysize1 = yysize + yytnamerr (0, yytname[yyx]);
1115 if (! (yysize <= yysize1
1116 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
1117 return 2;
1118 yysize = yysize1;
1119 }
1120 }
1121 }
1122
1123 switch (yycount)
1124 {
1125# define YYCASE_(N, S) \
1126 case N: \
1127 yyformat = S; \
1128 break
1129 YYCASE_(0, YY_("syntax error"));
1130 YYCASE_(1, YY_("syntax error, unexpected %s"));
1131 YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
1132 YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
1133 YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
1134 YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
1135# undef YYCASE_
1136 }
1137
1138 yysize1 = yysize + yystrlen (yyformat);
1139 if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
1140 return 2;
1141 yysize = yysize1;
1142
1143 if (*yymsg_alloc < yysize)
1144 {
1145 *yymsg_alloc = 2 * yysize;
1146 if (! (yysize <= *yymsg_alloc
1147 && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
1148 *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
1149 return 1;
1150 }
1151
1152 /* Avoid sprintf, as that infringes on the user's name space.
1153 Don't have undefined behavior even if the translation
1154 produced a string with the wrong number of "%s"s. */
1155 {
1156 char *yyp = *yymsg;
1157 int yyi = 0;
1158 while ((*yyp = *yyformat) != '\0')
1159 if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
1160 {
1161 yyp += yytnamerr (yyp, yyarg[yyi++]);
1162 yyformat += 2;
1163 }
1164 else
1165 {
1166 yyp++;
1167 yyformat++;
1168 }
1169 }
1170 return 0;
1171}
1172#endif /* YYERROR_VERBOSE */
1173
1174/*-----------------------------------------------.
1175| Release the memory associated to this symbol. |
1176`-----------------------------------------------*/
1177
1178/*ARGSUSED*/
1179#if (defined __STDC__ || defined __C99__FUNC__ \
1180 || defined __cplusplus || defined _MSC_VER)
1181static void
1182yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
1183#else
1184static void
1185yydestruct (yymsg, yytype, yyvaluep)
1186 const char *yymsg;
1187 int yytype;
1188 YYSTYPE *yyvaluep;
1189#endif
1190{
1191 YYUSE (yyvaluep);
1192
1193 if (!yymsg)
1194 yymsg = "Deleting";
1195 YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
1196
1197 switch (yytype)
1198 {
1199
1200 default:
1201 break;
1202 }
1203}
1204
1205
1206/* Prevent warnings from -Wmissing-prototypes. */
1207#ifdef YYPARSE_PARAM
1208#if defined __STDC__ || defined __cplusplus
1209int yyparse (void *YYPARSE_PARAM);
1210#else
1211int yyparse ();
1212#endif
1213#else /* ! YYPARSE_PARAM */
1214#if defined __STDC__ || defined __cplusplus
1215int yyparse (void);
1216#else
1217int yyparse ();
1218#endif
1219#endif /* ! YYPARSE_PARAM */
1220
1221
1222/* The lookahead symbol. */
1223int yychar;
1224
1225/* The semantic value of the lookahead symbol. */
1226YYSTYPE yylval;
1227
1228/* Number of syntax errors so far. */
1229int yynerrs;
1230
1231
1232/*----------.
1233| yyparse. |
1234`----------*/
1235
1236#ifdef YYPARSE_PARAM
1237#if (defined __STDC__ || defined __C99__FUNC__ \
1238 || defined __cplusplus || defined _MSC_VER)
1239int
1240yyparse (void *YYPARSE_PARAM)
1241#else
1242int
1243yyparse (YYPARSE_PARAM)
1244 void *YYPARSE_PARAM;
1245#endif
1246#else /* ! YYPARSE_PARAM */
1247#if (defined __STDC__ || defined __C99__FUNC__ \
1248 || defined __cplusplus || defined _MSC_VER)
1249int
1250yyparse (void)
1251#else
1252int
1253yyparse ()
1254
1255#endif
1256#endif
1257{
1258 int yystate;
1259 /* Number of tokens to shift before error messages enabled. */
1260 int yyerrstatus;
1261
1262 /* The stacks and their tools:
1263 `yyss': related to states.
1264 `yyvs': related to semantic values.
1265
1266 Refer to the stacks thru separate pointers, to allow yyoverflow
1267 to reallocate them elsewhere. */
1268
1269 /* The state stack. */
1270 yytype_int16 yyssa[YYINITDEPTH];
1271 yytype_int16 *yyss;
1272 yytype_int16 *yyssp;
1273
1274 /* The semantic value stack. */
1275 YYSTYPE yyvsa[YYINITDEPTH];
1276 YYSTYPE *yyvs;
1277 YYSTYPE *yyvsp;
1278
1279 YYSIZE_T yystacksize;
1280
1281 int yyn;
1282 int yyresult;
1283 /* Lookahead token as an internal (translated) token number. */
1284 int yytoken;
1285 /* The variables used to return semantic value and location from the
1286 action routines. */
1287 YYSTYPE yyval;
1288
1289#if YYERROR_VERBOSE
1290 /* Buffer for error messages, and its allocated size. */
1291 char yymsgbuf[128];
1292 char *yymsg = yymsgbuf;
1293 YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
1294#endif
1295
1296#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
1297
1298 /* The number of symbols on the RHS of the reduced rule.
1299 Keep to zero when no symbol should be popped. */
1300 int yylen = 0;
1301
1302 yytoken = 0;
1303 yyss = yyssa;
1304 yyvs = yyvsa;
1305 yystacksize = YYINITDEPTH;
1306
1307 YYDPRINTF ((stderr, "Starting parse\n"));
1308
1309 yystate = 0;
1310 yyerrstatus = 0;
1311 yynerrs = 0;
1312 yychar = YYEMPTY; /* Cause a token to be read. */
1313
1314 /* Initialize stack pointers.
1315 Waste one element of value and location stack
1316 so that they stay on the same level as the state stack.
1317 The wasted elements are never initialized. */
1318 yyssp = yyss;
1319 yyvsp = yyvs;
1320
1321 goto yysetstate;
1322
1323/*------------------------------------------------------------.
1324| yynewstate -- Push a new state, which is found in yystate. |
1325`------------------------------------------------------------*/
1326 yynewstate:
1327 /* In all cases, when you get here, the value and location stacks
1328 have just been pushed. So pushing a state here evens the stacks. */
1329 yyssp++;
1330
1331 yysetstate:
1332 *yyssp = yystate;
1333
1334 if (yyss + yystacksize - 1 <= yyssp)
1335 {
1336 /* Get the current used size of the three stacks, in elements. */
1337 YYSIZE_T yysize = yyssp - yyss + 1;
1338
1339#ifdef yyoverflow
1340 {
1341 /* Give user a chance to reallocate the stack. Use copies of
1342 these so that the &'s don't force the real ones into
1343 memory. */
1344 YYSTYPE *yyvs1 = yyvs;
1345 yytype_int16 *yyss1 = yyss;
1346
1347 /* Each stack pointer address is followed by the size of the
1348 data in use in that stack, in bytes. This used to be a
1349 conditional around just the two extra args, but that might
1350 be undefined if yyoverflow is a macro. */
1351 yyoverflow (YY_("memory exhausted"),
1352 &yyss1, yysize * sizeof (*yyssp),
1353 &yyvs1, yysize * sizeof (*yyvsp),
1354 &yystacksize);
1355
1356 yyss = yyss1;
1357 yyvs = yyvs1;
1358 }
1359#else /* no yyoverflow */
1360# ifndef YYSTACK_RELOCATE
1361 goto yyexhaustedlab;
1362# else
1363 /* Extend the stack our own way. */
1364 if (YYMAXDEPTH <= yystacksize)
1365 goto yyexhaustedlab;
1366 yystacksize *= 2;
1367 if (YYMAXDEPTH < yystacksize)
1368 yystacksize = YYMAXDEPTH;
1369
1370 {
1371 yytype_int16 *yyss1 = yyss;
1372 union yyalloc *yyptr =
1373 (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
1374 if (! yyptr)
1375 goto yyexhaustedlab;
1376 YYSTACK_RELOCATE (yyss_alloc, yyss);
1377 YYSTACK_RELOCATE (yyvs_alloc, yyvs);
1378# undef YYSTACK_RELOCATE
1379 if (yyss1 != yyssa)
1380 YYSTACK_FREE (yyss1);
1381 }
1382# endif
1383#endif /* no yyoverflow */
1384
1385 yyssp = yyss + yysize - 1;
1386 yyvsp = yyvs + yysize - 1;
1387
1388 YYDPRINTF ((stderr, "Stack size increased to %lu\n",
1389 (unsigned long int) yystacksize));
1390
1391 if (yyss + yystacksize - 1 <= yyssp)
1392 YYABORT;
1393 }
1394
1395 YYDPRINTF ((stderr, "Entering state %d\n", yystate));
1396
1397 if (yystate == YYFINAL)
1398 YYACCEPT;
1399
1400 goto yybackup;
1401
1402/*-----------.
1403| yybackup. |
1404`-----------*/
1405yybackup:
1406
1407 /* Do appropriate processing given the current state. Read a
1408 lookahead token if we need one and don't already have one. */
1409
1410 /* First try to decide what to do without reference to lookahead token. */
1411 yyn = yypact[yystate];
1412 if (yypact_value_is_default (yyn))
1413 goto yydefault;
1414
1415 /* Not known => get a lookahead token if don't already have one. */
1416
1417 /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
1418 if (yychar == YYEMPTY)
1419 {
1420 YYDPRINTF ((stderr, "Reading a token: "));
1421 yychar = YYLEX;
1422 }
1423
1424 if (yychar <= YYEOF)
1425 {
1426 yychar = yytoken = YYEOF;
1427 YYDPRINTF ((stderr, "Now at end of input.\n"));
1428 }
1429 else
1430 {
1431 yytoken = YYTRANSLATE (yychar);
1432 YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
1433 }
1434
1435 /* If the proper action on seeing token YYTOKEN is to reduce or to
1436 detect an error, take that action. */
1437 yyn += yytoken;
1438 if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
1439 goto yydefault;
1440 yyn = yytable[yyn];
1441 if (yyn <= 0)
1442 {
1443 if (yytable_value_is_error (yyn))
1444 goto yyerrlab;
1445 yyn = -yyn;
1446 goto yyreduce;
1447 }
1448
1449 /* Count tokens shifted since error; after three, turn off error
1450 status. */
1451 if (yyerrstatus)
1452 yyerrstatus--;
1453
1454 /* Shift the lookahead token. */
1455 YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
1456
1457 /* Discard the shifted token. */
1458 yychar = YYEMPTY;
1459
1460 yystate = yyn;
1461 *++yyvsp = yylval;
1462
1463 goto yynewstate;
1464
1465
1466/*-----------------------------------------------------------.
1467| yydefault -- do the default action for the current state. |
1468`-----------------------------------------------------------*/
1469yydefault:
1470 yyn = yydefact[yystate];
1471 if (yyn == 0)
1472 goto yyerrlab;
1473 goto yyreduce;
1474
1475
1476/*-----------------------------.
1477| yyreduce -- Do a reduction. |
1478`-----------------------------*/
1479yyreduce:
1480 /* yyn is the number of a rule to reduce with. */
1481 yylen = yyr2[yyn];
1482
1483 /* If YYLEN is nonzero, implement the default value of the action:
1484 `$$ = $1'.
1485
1486 Otherwise, the following line sets YYVAL to garbage.
1487 This behavior is undocumented and Bison
1488 users should not rely upon it. Assigning to YYVAL
1489 unconditionally makes the parser a bit smaller, and it avoids a
1490 GCC warning that YYVAL may be used uninitialized. */
1491 yyval = yyvsp[1-yylen];
1492
1493
1494 YY_REDUCE_PRINT (yyn);
1495 switch (yyn)
1496 {
1497 case 11:
1498
1499/* Line 1806 of yacc.c */
1500#line 133 "lib/conf-parse.y"
1501 { sensors_bus new_el;
1502 new_el.line = (yyvsp[(1) - (3)].line);
1503 new_el.bus = (yyvsp[(2) - (3)].bus);
1504 new_el.adapter = (yyvsp[(3) - (3)].name);
1505 bus_add_el(&new_el);
1506 }
1507 break;
1508
1509 case 12:
1510
1511/* Line 1806 of yacc.c */
1512#line 142 "lib/conf-parse.y"
1513 { sensors_label new_el;
1514 if (!current_chip) {
1515 sensors_yyerror("Label statement before first chip statement");
1516 free((yyvsp[(2) - (3)].name));
1517 free((yyvsp[(3) - (3)].name));
1518 YYERROR;
1519 }
1520 new_el.line = (yyvsp[(1) - (3)].line);
1521 new_el.name = (yyvsp[(2) - (3)].name);
1522 new_el.value = (yyvsp[(3) - (3)].name);
1523 label_add_el(&new_el);
1524 }
1525 break;
1526
1527 case 13:
1528
1529/* Line 1806 of yacc.c */
1530#line 157 "lib/conf-parse.y"
1531 { sensors_set new_el;
1532 if (!current_chip) {
1533 sensors_yyerror("Set statement before first chip statement");
1534 free((yyvsp[(2) - (3)].name));
1535 sensors_free_expr((yyvsp[(3) - (3)].expr));
1536 YYERROR;
1537 }
1538 new_el.line = (yyvsp[(1) - (3)].line);
1539 new_el.name = (yyvsp[(2) - (3)].name);
1540 new_el.value = (yyvsp[(3) - (3)].expr);
1541 set_add_el(&new_el);
1542 }
1543 break;
1544
1545 case 14:
1546
1547/* Line 1806 of yacc.c */
1548#line 172 "lib/conf-parse.y"
1549 { sensors_compute new_el;
1550 if (!current_chip) {
1551 sensors_yyerror("Compute statement before first chip statement");
1552 free((yyvsp[(2) - (5)].name));
1553 sensors_free_expr((yyvsp[(3) - (5)].expr));
1554 sensors_free_expr((yyvsp[(5) - (5)].expr));
1555 YYERROR;
1556 }
1557 new_el.line = (yyvsp[(1) - (5)].line);
1558 new_el.name = (yyvsp[(2) - (5)].name);
1559 new_el.from_proc = (yyvsp[(3) - (5)].expr);
1560 new_el.to_proc = (yyvsp[(5) - (5)].expr);
1561 compute_add_el(&new_el);
1562 }
1563 break;
1564
1565 case 15:
1566
1567/* Line 1806 of yacc.c */
1568#line 189 "lib/conf-parse.y"
1569 { sensors_ignore new_el;
1570 if (!current_chip) {
1571 sensors_yyerror("Ignore statement before first chip statement");
1572 free((yyvsp[(2) - (2)].name));
1573 YYERROR;
1574 }
1575 new_el.line = (yyvsp[(1) - (2)].line);
1576 new_el.name = (yyvsp[(2) - (2)].name);
1577 ignore_add_el(&new_el);
1578 }
1579 break;
1580
1581 case 16:
1582
1583/* Line 1806 of yacc.c */
1584#line 202 "lib/conf-parse.y"
1585 { sensors_chip new_el;
1586 new_el.line = (yyvsp[(1) - (2)].line);
1587 new_el.labels = NULL;
1588 new_el.sets = NULL;
1589 new_el.computes = NULL;
1590 new_el.ignores = NULL;
1591 new_el.labels_count = new_el.labels_max = 0;
1592 new_el.sets_count = new_el.sets_max = 0;
1593 new_el.computes_count = new_el.computes_max = 0;
1594 new_el.ignores_count = new_el.ignores_max = 0;
1595 new_el.chips = (yyvsp[(2) - (2)].chips);
1596 chip_add_el(&new_el);
1597 current_chip = sensors_config_chips +
1598 sensors_config_chips_count - 1;
1599 }
1600 break;
1601
1602 case 17:
1603
1604/* Line 1806 of yacc.c */
1605#line 220 "lib/conf-parse.y"
1606 {
1607 (yyval.chips).fits = NULL;
1608 (yyval.chips).fits_count = (yyval.chips).fits_max = 0;
1609 fits_add_el(&(yyvsp[(1) - (1)].chip),(yyval.chips));
1610 }
1611 break;
1612
1613 case 18:
1614
1615/* Line 1806 of yacc.c */
1616#line 226 "lib/conf-parse.y"
1617 { (yyval.chips) = (yyvsp[(1) - (2)].chips);
1618 fits_add_el(&(yyvsp[(2) - (2)].chip),(yyval.chips));
1619 }
1620 break;
1621
1622 case 19:
1623
1624/* Line 1806 of yacc.c */
1625#line 232 "lib/conf-parse.y"
1626 { (yyval.expr) = malloc_expr();
1627 (yyval.expr)->data.val = (yyvsp[(1) - (1)].value);
1628 (yyval.expr)->kind = sensors_kind_val;
1629 }
1630 break;
1631
1632 case 20:
1633
1634/* Line 1806 of yacc.c */
1635#line 237 "lib/conf-parse.y"
1636 { (yyval.expr) = malloc_expr();
1637 (yyval.expr)->data.var = (yyvsp[(1) - (1)].name);
1638 (yyval.expr)->kind = sensors_kind_var;
1639 }
1640 break;
1641
1642 case 21:
1643
1644/* Line 1806 of yacc.c */
1645#line 242 "lib/conf-parse.y"
1646 { (yyval.expr) = malloc_expr();
1647 (yyval.expr)->kind = sensors_kind_source;
1648 }
1649 break;
1650
1651 case 22:
1652
1653/* Line 1806 of yacc.c */
1654#line 246 "lib/conf-parse.y"
1655 { (yyval.expr) = malloc_expr();
1656 (yyval.expr)->kind = sensors_kind_sub;
1657 (yyval.expr)->data.subexpr.op = sensors_add;
1658 (yyval.expr)->data.subexpr.sub1 = (yyvsp[(1) - (3)].expr);
1659 (yyval.expr)->data.subexpr.sub2 = (yyvsp[(3) - (3)].expr);
1660 }
1661 break;
1662
1663 case 23:
1664
1665/* Line 1806 of yacc.c */
1666#line 253 "lib/conf-parse.y"
1667 { (yyval.expr) = malloc_expr();
1668 (yyval.expr)->kind = sensors_kind_sub;
1669 (yyval.expr)->data.subexpr.op = sensors_sub;
1670 (yyval.expr)->data.subexpr.sub1 = (yyvsp[(1) - (3)].expr);
1671 (yyval.expr)->data.subexpr.sub2 = (yyvsp[(3) - (3)].expr);
1672 }
1673 break;
1674
1675 case 24:
1676
1677/* Line 1806 of yacc.c */
1678#line 260 "lib/conf-parse.y"
1679 { (yyval.expr) = malloc_expr();
1680 (yyval.expr)->kind = sensors_kind_sub;
1681 (yyval.expr)->data.subexpr.op = sensors_multiply;
1682 (yyval.expr)->data.subexpr.sub1 = (yyvsp[(1) - (3)].expr);
1683 (yyval.expr)->data.subexpr.sub2 = (yyvsp[(3) - (3)].expr);
1684 }
1685 break;
1686
1687 case 25:
1688
1689/* Line 1806 of yacc.c */
1690#line 267 "lib/conf-parse.y"
1691 { (yyval.expr) = malloc_expr();
1692 (yyval.expr)->kind = sensors_kind_sub;
1693 (yyval.expr)->data.subexpr.op = sensors_divide;
1694 (yyval.expr)->data.subexpr.sub1 = (yyvsp[(1) - (3)].expr);
1695 (yyval.expr)->data.subexpr.sub2 = (yyvsp[(3) - (3)].expr);
1696 }
1697 break;
1698
1699 case 26:
1700
1701/* Line 1806 of yacc.c */
1702#line 274 "lib/conf-parse.y"
1703 { (yyval.expr) = malloc_expr();
1704 (yyval.expr)->kind = sensors_kind_sub;
1705 (yyval.expr)->data.subexpr.op = sensors_negate;
1706 (yyval.expr)->data.subexpr.sub1 = (yyvsp[(2) - (2)].expr);
1707 (yyval.expr)->data.subexpr.sub2 = NULL;
1708 }
1709 break;
1710
1711 case 27:
1712
1713/* Line 1806 of yacc.c */
1714#line 281 "lib/conf-parse.y"
1715 { (yyval.expr) = (yyvsp[(2) - (3)].expr); }
1716 break;
1717
1718 case 28:
1719
1720/* Line 1806 of yacc.c */
1721#line 283 "lib/conf-parse.y"
1722 { (yyval.expr) = malloc_expr();
1723 (yyval.expr)->kind = sensors_kind_sub;
1724 (yyval.expr)->data.subexpr.op = sensors_exp;
1725 (yyval.expr)->data.subexpr.sub1 = (yyvsp[(2) - (2)].expr);
1726 (yyval.expr)->data.subexpr.sub2 = NULL;
1727 }
1728 break;
1729
1730 case 29:
1731
1732/* Line 1806 of yacc.c */
1733#line 290 "lib/conf-parse.y"
1734 { (yyval.expr) = malloc_expr();
1735 (yyval.expr)->kind = sensors_kind_sub;
1736 (yyval.expr)->data.subexpr.op = sensors_log;
1737 (yyval.expr)->data.subexpr.sub1 = (yyvsp[(2) - (2)].expr);
1738 (yyval.expr)->data.subexpr.sub2 = NULL;
1739 }
1740 break;
1741
1742 case 30:
1743
1744/* Line 1806 of yacc.c */
1745#line 299 "lib/conf-parse.y"
1746 { int res = sensors_parse_bus_id((yyvsp[(1) - (1)].name),&(yyval.bus));
1747 free((yyvsp[(1) - (1)].name));
1748 if (res) {
1749 sensors_yyerror("Parse error in bus id");
1750 YYERROR;
1751 }
1752 }
1753 break;
1754
1755 case 31:
1756
1757/* Line 1806 of yacc.c */
1758#line 309 "lib/conf-parse.y"
1759 { (yyval.name) = (yyvsp[(1) - (1)].name); }
1760 break;
1761
1762 case 32:
1763
1764/* Line 1806 of yacc.c */
1765#line 313 "lib/conf-parse.y"
1766 { (yyval.name) = (yyvsp[(1) - (1)].name); }
1767 break;
1768
1769 case 33:
1770
1771/* Line 1806 of yacc.c */
1772#line 317 "lib/conf-parse.y"
1773 { (yyval.name) = (yyvsp[(1) - (1)].name); }
1774 break;
1775
1776 case 34:
1777
1778/* Line 1806 of yacc.c */
1779#line 321 "lib/conf-parse.y"
1780 { int res = sensors_parse_chip_name((yyvsp[(1) - (1)].name),&(yyval.chip));
1781 free((yyvsp[(1) - (1)].name));
1782 if (res) {
1783 sensors_yyerror("Parse error in chip name");
1784 YYERROR;
1785 }
1786 }
1787 break;
1788
1789
1790
1791/* Line 1806 of yacc.c */
1792#line 1793 "lib/conf-parse.c"
1793 default: break;
1794 }
1795 /* User semantic actions sometimes alter yychar, and that requires
1796 that yytoken be updated with the new translation. We take the
1797 approach of translating immediately before every use of yytoken.
1798 One alternative is translating here after every semantic action,
1799 but that translation would be missed if the semantic action invokes
1800 YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
1801 if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
1802 incorrect destructor might then be invoked immediately. In the
1803 case of YYERROR or YYBACKUP, subsequent parser actions might lead
1804 to an incorrect destructor call or verbose syntax error message
1805 before the lookahead is translated. */
1806 YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
1807
1808 YYPOPSTACK (yylen);
1809 yylen = 0;
1810 YY_STACK_PRINT (yyss, yyssp);
1811
1812 *++yyvsp = yyval;
1813
1814 /* Now `shift' the result of the reduction. Determine what state
1815 that goes to, based on the state we popped back to and the rule
1816 number reduced by. */
1817
1818 yyn = yyr1[yyn];
1819
1820 yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
1821 if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
1822 yystate = yytable[yystate];
1823 else
1824 yystate = yydefgoto[yyn - YYNTOKENS];
1825
1826 goto yynewstate;
1827
1828
1829/*------------------------------------.
1830| yyerrlab -- here on detecting error |
1831`------------------------------------*/
1832yyerrlab:
1833 /* Make sure we have latest lookahead translation. See comments at
1834 user semantic actions for why this is necessary. */
1835 yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
1836
1837 /* If not already recovering from an error, report this error. */
1838 if (!yyerrstatus)
1839 {
1840 ++yynerrs;
1841#if ! YYERROR_VERBOSE
1842 yyerror (YY_("syntax error"));
1843#else
1844# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
1845 yyssp, yytoken)
1846 {
1847 char const *yymsgp = YY_("syntax error");
1848 int yysyntax_error_status;
1849 yysyntax_error_status = YYSYNTAX_ERROR;
1850 if (yysyntax_error_status == 0)
1851 yymsgp = yymsg;
1852 else if (yysyntax_error_status == 1)
1853 {
1854 if (yymsg != yymsgbuf)
1855 YYSTACK_FREE (yymsg);
1856 yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
1857 if (!yymsg)
1858 {
1859 yymsg = yymsgbuf;
1860 yymsg_alloc = sizeof yymsgbuf;
1861 yysyntax_error_status = 2;
1862 }
1863 else
1864 {
1865 yysyntax_error_status = YYSYNTAX_ERROR;
1866 yymsgp = yymsg;
1867 }
1868 }
1869 yyerror (yymsgp);
1870 if (yysyntax_error_status == 2)
1871 goto yyexhaustedlab;
1872 }
1873# undef YYSYNTAX_ERROR
1874#endif
1875 }
1876
1877
1878
1879 if (yyerrstatus == 3)
1880 {
1881 /* If just tried and failed to reuse lookahead token after an
1882 error, discard it. */
1883
1884 if (yychar <= YYEOF)
1885 {
1886 /* Return failure if at end of input. */
1887 if (yychar == YYEOF)
1888 YYABORT;
1889 }
1890 else
1891 {
1892 yydestruct ("Error: discarding",
1893 yytoken, &yylval);
1894 yychar = YYEMPTY;
1895 }
1896 }
1897
1898 /* Else will try to reuse lookahead token after shifting the error
1899 token. */
1900 goto yyerrlab1;
1901
1902
1903/*---------------------------------------------------.
1904| yyerrorlab -- error raised explicitly by YYERROR. |
1905`---------------------------------------------------*/
1906yyerrorlab:
1907
1908 /* Pacify compilers like GCC when the user code never invokes
1909 YYERROR and the label yyerrorlab therefore never appears in user
1910 code. */
1911 if (/*CONSTCOND*/ 0)
1912 goto yyerrorlab;
1913
1914 /* Do not reclaim the symbols of the rule which action triggered
1915 this YYERROR. */
1916 YYPOPSTACK (yylen);
1917 yylen = 0;
1918 YY_STACK_PRINT (yyss, yyssp);
1919 yystate = *yyssp;
1920 goto yyerrlab1;
1921
1922
1923/*-------------------------------------------------------------.
1924| yyerrlab1 -- common code for both syntax error and YYERROR. |
1925`-------------------------------------------------------------*/
1926yyerrlab1:
1927 yyerrstatus = 3; /* Each real token shifted decrements this. */
1928
1929 for (;;)
1930 {
1931 yyn = yypact[yystate];
1932 if (!yypact_value_is_default (yyn))
1933 {
1934 yyn += YYTERROR;
1935 if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
1936 {
1937 yyn = yytable[yyn];
1938 if (0 < yyn)
1939 break;
1940 }
1941 }
1942
1943 /* Pop the current state because it cannot handle the error token. */
1944 if (yyssp == yyss)
1945 YYABORT;
1946
1947
1948 yydestruct ("Error: popping",
1949 yystos[yystate], yyvsp);
1950 YYPOPSTACK (1);
1951 yystate = *yyssp;
1952 YY_STACK_PRINT (yyss, yyssp);
1953 }
1954
1955 *++yyvsp = yylval;
1956
1957
1958 /* Shift the error token. */
1959 YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
1960
1961 yystate = yyn;
1962 goto yynewstate;
1963
1964
1965/*-------------------------------------.
1966| yyacceptlab -- YYACCEPT comes here. |
1967`-------------------------------------*/
1968yyacceptlab:
1969 yyresult = 0;
1970 goto yyreturn;
1971
1972/*-----------------------------------.
1973| yyabortlab -- YYABORT comes here. |
1974`-----------------------------------*/
1975yyabortlab:
1976 yyresult = 1;
1977 goto yyreturn;
1978
1979#if !defined(yyoverflow) || YYERROR_VERBOSE
1980/*-------------------------------------------------.
1981| yyexhaustedlab -- memory exhaustion comes here. |
1982`-------------------------------------------------*/
1983yyexhaustedlab:
1984 yyerror (YY_("memory exhausted"));
1985 yyresult = 2;
1986 /* Fall through. */
1987#endif
1988
1989yyreturn:
1990 if (yychar != YYEMPTY)
1991 {
1992 /* Make sure we have latest lookahead translation. See comments at
1993 user semantic actions for why this is necessary. */
1994 yytoken = YYTRANSLATE (yychar);
1995 yydestruct ("Cleanup: discarding lookahead",
1996 yytoken, &yylval);
1997 }
1998 /* Do not reclaim the symbols of the rule which action triggered
1999 this YYABORT or YYACCEPT. */
2000 YYPOPSTACK (yylen);
2001 YY_STACK_PRINT (yyss, yyssp);
2002 while (yyssp != yyss)
2003 {
2004 yydestruct ("Cleanup: popping",
2005 yystos[*yyssp], yyvsp);
2006 YYPOPSTACK (1);
2007 }
2008#ifndef yyoverflow
2009 if (yyss != yyssa)
2010 YYSTACK_FREE (yyss);
2011#endif
2012#if YYERROR_VERBOSE
2013 if (yymsg != yymsgbuf)
2014 YYSTACK_FREE (yymsg);
2015#endif
2016 /* Make sure YYID is used. */
2017 return YYID (yyresult);
2018}
2019
2020
2021
2022/* Line 2067 of yacc.c */
2023#line 330 "lib/conf-parse.y"
2024
2025
2026void sensors_yyerror(const char *err)
2027{
2028 if (sensors_lex_error[0]) {
2029 sensors_parse_error_wfn(sensors_lex_error, sensors_yyfilename, sensors_yylineno);
2030 sensors_lex_error[0] = '\0';
2031 } else
2032 sensors_parse_error_wfn(err, sensors_yyfilename, sensors_yylineno);
2033}
2034
2035sensors_expr *malloc_expr(void)
2036{
2037 sensors_expr *res = malloc(sizeof(sensors_expr));
2038 if (! res)
2039 sensors_fatal_error(__func__, "Allocating a new expression");
2040 return res;
2041}
2042
diff --git a/tools/gator/daemon/libsensors/conf-parse.h b/tools/gator/daemon/libsensors/conf-parse.h
new file mode 100644
index 00000000000..89c9c1a0d59
--- /dev/null
+++ b/tools/gator/daemon/libsensors/conf-parse.h
@@ -0,0 +1,84 @@
1/* A Bison parser, made by GNU Bison 2.5. */
2
3/* Bison interface for Yacc-like parsers in C
4
5 Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
6
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19
20/* As a special exception, you may create a larger work that contains
21 part or all of the Bison parser skeleton and distribute that work
22 under terms of your choice, so long as that work isn't itself a
23 parser generator using the skeleton or a modified version thereof
24 as a parser skeleton. Alternatively, if you modify or redistribute
25 the parser skeleton itself, you may (at your option) remove this
26 special exception, which will cause the skeleton and the resulting
27 Bison output files to be licensed under the GNU General Public
28 License without this special exception.
29
30 This special exception was added by the Free Software Foundation in
31 version 2.2 of Bison. */
32
33
34/* Tokens. */
35#ifndef YYTOKENTYPE
36# define YYTOKENTYPE
37 /* Put the tokens into the symbol table, so that GDB and other debuggers
38 know about them. */
39 enum yytokentype {
40 NEG = 258,
41 EOL = 259,
42 BUS = 260,
43 LABEL = 261,
44 SET = 262,
45 CHIP = 263,
46 COMPUTE = 264,
47 IGNORE = 265,
48 FLOAT = 266,
49 NAME = 267,
50 ERROR = 268
51 };
52#endif
53
54
55
56#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
57typedef union YYSTYPE
58{
59
60/* Line 2068 of yacc.c */
61#line 79 "lib/conf-parse.y"
62
63 double value;
64 char *name;
65 void *nothing;
66 sensors_chip_name_list chips;
67 sensors_expr *expr;
68 sensors_bus_id bus;
69 sensors_chip_name chip;
70 sensors_config_line line;
71
72
73
74/* Line 2068 of yacc.c */
75#line 76 "lib/conf-parse.h"
76} YYSTYPE;
77# define YYSTYPE_IS_TRIVIAL 1
78# define yystype YYSTYPE /* obsolescent; will be withdrawn */
79# define YYSTYPE_IS_DECLARED 1
80#endif
81
82extern YYSTYPE sensors_yylval;
83
84
diff --git a/tools/gator/daemon/libsensors/conf-parse.y b/tools/gator/daemon/libsensors/conf-parse.y
new file mode 100644
index 00000000000..1937f544dc6
--- /dev/null
+++ b/tools/gator/daemon/libsensors/conf-parse.y
@@ -0,0 +1,347 @@
1%{
2/*
3 conf-parse.y - Part of libsensors, a Linux library for reading sensor data.
4 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301 USA.
20*/
21
22#define YYERROR_VERBOSE
23
24#include <stdio.h>
25#include <string.h>
26#include <stdlib.h>
27
28#include "data.h"
29#include "general.h"
30#include "error.h"
31#include "conf.h"
32#include "access.h"
33#include "init.h"
34
35static void sensors_yyerror(const char *err);
36static sensors_expr *malloc_expr(void);
37
38static sensors_chip *current_chip = NULL;
39
40#define bus_add_el(el) sensors_add_array_el(el,\
41 &sensors_config_busses,\
42 &sensors_config_busses_count,\
43 &sensors_config_busses_max,\
44 sizeof(sensors_bus))
45#define label_add_el(el) sensors_add_array_el(el,\
46 &current_chip->labels,\
47 &current_chip->labels_count,\
48 &current_chip->labels_max,\
49 sizeof(sensors_label));
50#define set_add_el(el) sensors_add_array_el(el,\
51 &current_chip->sets,\
52 &current_chip->sets_count,\
53 &current_chip->sets_max,\
54 sizeof(sensors_set));
55#define compute_add_el(el) sensors_add_array_el(el,\
56 &current_chip->computes,\
57 &current_chip->computes_count,\
58 &current_chip->computes_max,\
59 sizeof(sensors_compute));
60#define ignore_add_el(el) sensors_add_array_el(el,\
61 &current_chip->ignores,\
62 &current_chip->ignores_count,\
63 &current_chip->ignores_max,\
64 sizeof(sensors_ignore));
65#define chip_add_el(el) sensors_add_array_el(el,\
66 &sensors_config_chips,\
67 &sensors_config_chips_count,\
68 &sensors_config_chips_max,\
69 sizeof(sensors_chip));
70
71#define fits_add_el(el,list) sensors_add_array_el(el,\
72 &(list).fits,\
73 &(list).fits_count,\
74 &(list).fits_max, \
75 sizeof(sensors_chip_name));
76
77%}
78
79%union {
80 double value;
81 char *name;
82 void *nothing;
83 sensors_chip_name_list chips;
84 sensors_expr *expr;
85 sensors_bus_id bus;
86 sensors_chip_name chip;
87 sensors_config_line line;
88}
89
90%left <nothing> '-' '+'
91%left <nothing> '*' '/'
92%left <nothing> NEG
93%right <nothing> '^' '`'
94
95%token <nothing> ','
96%token <nothing> EOL
97%token <line> BUS
98%token <line> LABEL
99%token <line> SET
100%token <line> CHIP
101%token <line> COMPUTE
102%token <line> IGNORE
103%token <value> FLOAT
104%token <name> NAME
105%token <nothing> ERROR
106
107%type <chips> chip_name_list
108%type <expr> expression
109%type <bus> bus_id
110%type <name> adapter_name
111%type <name> function_name
112%type <name> string
113%type <chip> chip_name
114
115%start input
116
117%%
118
119input: /* empty */
120 | input line
121;
122
123line: bus_statement EOL
124 | label_statement EOL
125 | set_statement EOL
126 | chip_statement EOL
127 | compute_statement EOL
128 | ignore_statement EOL
129 | error EOL
130;
131
132bus_statement: BUS bus_id adapter_name
133 { sensors_bus new_el;
134 new_el.line = $1;
135 new_el.bus = $2;
136 new_el.adapter = $3;
137 bus_add_el(&new_el);
138 }
139;
140
141label_statement: LABEL function_name string
142 { sensors_label new_el;
143 if (!current_chip) {
144 sensors_yyerror("Label statement before first chip statement");
145 free($2);
146 free($3);
147 YYERROR;
148 }
149 new_el.line = $1;
150 new_el.name = $2;
151 new_el.value = $3;
152 label_add_el(&new_el);
153 }
154;
155
156set_statement: SET function_name expression
157 { sensors_set new_el;
158 if (!current_chip) {
159 sensors_yyerror("Set statement before first chip statement");
160 free($2);
161 sensors_free_expr($3);
162 YYERROR;
163 }
164 new_el.line = $1;
165 new_el.name = $2;
166 new_el.value = $3;
167 set_add_el(&new_el);
168 }
169;
170
171compute_statement: COMPUTE function_name expression ',' expression
172 { sensors_compute new_el;
173 if (!current_chip) {
174 sensors_yyerror("Compute statement before first chip statement");
175 free($2);
176 sensors_free_expr($3);
177 sensors_free_expr($5);
178 YYERROR;
179 }
180 new_el.line = $1;
181 new_el.name = $2;
182 new_el.from_proc = $3;
183 new_el.to_proc = $5;
184 compute_add_el(&new_el);
185 }
186;
187
188ignore_statement: IGNORE function_name
189 { sensors_ignore new_el;
190 if (!current_chip) {
191 sensors_yyerror("Ignore statement before first chip statement");
192 free($2);
193 YYERROR;
194 }
195 new_el.line = $1;
196 new_el.name = $2;
197 ignore_add_el(&new_el);
198 }
199;
200
201chip_statement: CHIP chip_name_list
202 { sensors_chip new_el;
203 new_el.line = $1;
204 new_el.labels = NULL;
205 new_el.sets = NULL;
206 new_el.computes = NULL;
207 new_el.ignores = NULL;
208 new_el.labels_count = new_el.labels_max = 0;
209 new_el.sets_count = new_el.sets_max = 0;
210 new_el.computes_count = new_el.computes_max = 0;
211 new_el.ignores_count = new_el.ignores_max = 0;
212 new_el.chips = $2;
213 chip_add_el(&new_el);
214 current_chip = sensors_config_chips +
215 sensors_config_chips_count - 1;
216 }
217;
218
219chip_name_list: chip_name
220 {
221 $$.fits = NULL;
222 $$.fits_count = $$.fits_max = 0;
223 fits_add_el(&$1,$$);
224 }
225 | chip_name_list chip_name
226 { $$ = $1;
227 fits_add_el(&$2,$$);
228 }
229;
230
231expression: FLOAT
232 { $$ = malloc_expr();
233 $$->data.val = $1;
234 $$->kind = sensors_kind_val;
235 }
236 | NAME
237 { $$ = malloc_expr();
238 $$->data.var = $1;
239 $$->kind = sensors_kind_var;
240 }
241 | '@'
242 { $$ = malloc_expr();
243 $$->kind = sensors_kind_source;
244 }
245 | expression '+' expression
246 { $$ = malloc_expr();
247 $$->kind = sensors_kind_sub;
248 $$->data.subexpr.op = sensors_add;
249 $$->data.subexpr.sub1 = $1;
250 $$->data.subexpr.sub2 = $3;
251 }
252 | expression '-' expression
253 { $$ = malloc_expr();
254 $$->kind = sensors_kind_sub;
255 $$->data.subexpr.op = sensors_sub;
256 $$->data.subexpr.sub1 = $1;
257 $$->data.subexpr.sub2 = $3;
258 }
259 | expression '*' expression
260 { $$ = malloc_expr();
261 $$->kind = sensors_kind_sub;
262 $$->data.subexpr.op = sensors_multiply;
263 $$->data.subexpr.sub1 = $1;
264 $$->data.subexpr.sub2 = $3;
265 }
266 | expression '/' expression
267 { $$ = malloc_expr();
268 $$->kind = sensors_kind_sub;
269 $$->data.subexpr.op = sensors_divide;
270 $$->data.subexpr.sub1 = $1;
271 $$->data.subexpr.sub2 = $3;
272 }
273 | '-' expression %prec NEG
274 { $$ = malloc_expr();
275 $$->kind = sensors_kind_sub;
276 $$->data.subexpr.op = sensors_negate;
277 $$->data.subexpr.sub1 = $2;
278 $$->data.subexpr.sub2 = NULL;
279 }
280 | '(' expression ')'
281 { $$ = $2; }
282 | '^' expression
283 { $$ = malloc_expr();
284 $$->kind = sensors_kind_sub;
285 $$->data.subexpr.op = sensors_exp;
286 $$->data.subexpr.sub1 = $2;
287 $$->data.subexpr.sub2 = NULL;
288 }
289 | '`' expression
290 { $$ = malloc_expr();
291 $$->kind = sensors_kind_sub;
292 $$->data.subexpr.op = sensors_log;
293 $$->data.subexpr.sub1 = $2;
294 $$->data.subexpr.sub2 = NULL;
295 }
296;
297
298bus_id: NAME
299 { int res = sensors_parse_bus_id($1,&$$);
300 free($1);
301 if (res) {
302 sensors_yyerror("Parse error in bus id");
303 YYERROR;
304 }
305 }
306;
307
308adapter_name: NAME
309 { $$ = $1; }
310;
311
312function_name: NAME
313 { $$ = $1; }
314;
315
316string: NAME
317 { $$ = $1; }
318;
319
320chip_name: NAME
321 { int res = sensors_parse_chip_name($1,&$$);
322 free($1);
323 if (res) {
324 sensors_yyerror("Parse error in chip name");
325 YYERROR;
326 }
327 }
328;
329
330%%
331
332void sensors_yyerror(const char *err)
333{
334 if (sensors_lex_error[0]) {
335 sensors_parse_error_wfn(sensors_lex_error, sensors_yyfilename, sensors_yylineno);
336 sensors_lex_error[0] = '\0';
337 } else
338 sensors_parse_error_wfn(err, sensors_yyfilename, sensors_yylineno);
339}
340
341sensors_expr *malloc_expr(void)
342{
343 sensors_expr *res = malloc(sizeof(sensors_expr));
344 if (! res)
345 sensors_fatal_error(__func__, "Allocating a new expression");
346 return res;
347}
diff --git a/tools/gator/daemon/libsensors/conf.h b/tools/gator/daemon/libsensors/conf.h
new file mode 100644
index 00000000000..b7ce4f7ca83
--- /dev/null
+++ b/tools/gator/daemon/libsensors/conf.h
@@ -0,0 +1,34 @@
1/*
2 conf.h - Part of libsensors, a Linux library for reading sensor data.
3 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 MA 02110-1301 USA.
19*/
20
21#ifndef LIB_SENSORS_CONF_H
22#define LIB_SENSORS_CONF_H
23
24/* This is defined in conf-lex.l */
25int sensors_yylex(void);
26extern char sensors_lex_error[];
27extern const char *sensors_yyfilename;
28extern int sensors_yylineno;
29extern FILE *sensors_yyin;
30
31/* This is defined in conf-parse.y */
32int sensors_yyparse(void);
33
34#endif /* LIB_SENSORS_CONF_H */
diff --git a/tools/gator/daemon/libsensors/data.c b/tools/gator/daemon/libsensors/data.c
new file mode 100644
index 00000000000..cac9c8dc6eb
--- /dev/null
+++ b/tools/gator/daemon/libsensors/data.c
@@ -0,0 +1,278 @@
1/*
2 data.c - Part of libsensors, a Linux library for reading sensor data.
3 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
4 Copyright (C) 2007, 2009 Jean Delvare <khali@linux-fr.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301 USA.
20*/
21
22/*** This file modified by ARM on Jan 23, 2013 to move version.h to the current directory. ***/
23
24/* this define needed for strndup() */
25#define _GNU_SOURCE
26
27#include <stdlib.h>
28#include <string.h>
29
30#include "access.h"
31#include "error.h"
32#include "data.h"
33#include "sensors.h"
34#include "version.h"
35
36const char *libsensors_version = LM_VERSION;
37
38char **sensors_config_files = NULL;
39int sensors_config_files_count = 0;
40int sensors_config_files_max = 0;
41
42sensors_chip *sensors_config_chips = NULL;
43int sensors_config_chips_count = 0;
44int sensors_config_chips_subst = 0;
45int sensors_config_chips_max = 0;
46
47sensors_bus *sensors_config_busses = NULL;
48int sensors_config_busses_count = 0;
49int sensors_config_busses_max = 0;
50
51sensors_chip_features *sensors_proc_chips = NULL;
52int sensors_proc_chips_count = 0;
53int sensors_proc_chips_max = 0;
54
55sensors_bus *sensors_proc_bus = NULL;
56int sensors_proc_bus_count = 0;
57int sensors_proc_bus_max = 0;
58
59void sensors_free_chip_name(sensors_chip_name *chip)
60{
61 free(chip->prefix);
62}
63
64/*
65 Parse a chip name to the internal representation. These are valid names:
66
67 lm78-i2c-10-5e *-i2c-10-5e
68 lm78-i2c-10-* *-i2c-10-*
69 lm78-i2c-*-5e *-i2c-*-5e
70 lm78-i2c-*-* *-i2c-*-*
71 lm78-isa-10dd *-isa-10dd
72 lm78-isa-* *-isa-*
73 lm78-* *-*
74
75 Here 'lm78' can be any prefix. 'i2c' and 'isa' are
76 literal strings, just like all dashes '-' and wildcards '*'. '10' can
77 be any decimal i2c bus number. '5e' can be any hexadecimal i2c device
78 address, and '10dd' any hexadecimal isa address.
79
80 The 'prefix' part in the result is freshly allocated. All old contents
81 of res is overwritten. res itself is not allocated. In case of an error
82 return (ie. != 0), res is undefined, but all allocations are undone.
83*/
84
85int sensors_parse_chip_name(const char *name, sensors_chip_name *res)
86{
87 char *dash;
88
89 /* First, the prefix. It's either "*" or a real chip name. */
90 if (!strncmp(name, "*-", 2)) {
91 res->prefix = SENSORS_CHIP_NAME_PREFIX_ANY;
92 name += 2;
93 } else {
94 if (!(dash = strchr(name, '-')))
95 return -SENSORS_ERR_CHIP_NAME;
96 res->prefix = strndup(name, dash - name);
97 if (!res->prefix)
98 sensors_fatal_error(__func__,
99 "Allocating name prefix");
100 name = dash + 1;
101 }
102
103 /* Then we have either a sole "*" (all chips with this name) or a bus
104 type and an address. */
105 if (!strcmp(name, "*")) {
106 res->bus.type = SENSORS_BUS_TYPE_ANY;
107 res->bus.nr = SENSORS_BUS_NR_ANY;
108 res->addr = SENSORS_CHIP_NAME_ADDR_ANY;
109 return 0;
110 }
111
112 if (!(dash = strchr(name, '-')))
113 goto ERROR;
114 if (!strncmp(name, "i2c", dash - name))
115 res->bus.type = SENSORS_BUS_TYPE_I2C;
116 else if (!strncmp(name, "isa", dash - name))
117 res->bus.type = SENSORS_BUS_TYPE_ISA;
118 else if (!strncmp(name, "pci", dash - name))
119 res->bus.type = SENSORS_BUS_TYPE_PCI;
120 else if (!strncmp(name, "spi", dash - name))
121 res->bus.type = SENSORS_BUS_TYPE_SPI;
122 else if (!strncmp(name, "virtual", dash - name))
123 res->bus.type = SENSORS_BUS_TYPE_VIRTUAL;
124 else if (!strncmp(name, "acpi", dash - name))
125 res->bus.type = SENSORS_BUS_TYPE_ACPI;
126 else if (!strncmp(name, "hid", dash - name))
127 res->bus.type = SENSORS_BUS_TYPE_HID;
128 else
129 goto ERROR;
130 name = dash + 1;
131
132 /* Some bus types (i2c, spi) have an additional bus number.
133 For these, the next part is either a "*" (any bus of that type)
134 or a decimal number. */
135 switch (res->bus.type) {
136 case SENSORS_BUS_TYPE_I2C:
137 case SENSORS_BUS_TYPE_SPI:
138 case SENSORS_BUS_TYPE_HID:
139 if (!strncmp(name, "*-", 2)) {
140 res->bus.nr = SENSORS_BUS_NR_ANY;
141 name += 2;
142 break;
143 }
144
145 res->bus.nr = strtoul(name, &dash, 10);
146 if (*name == '\0' || *dash != '-' || res->bus.nr < 0)
147 goto ERROR;
148 name = dash + 1;
149 break;
150 default:
151 res->bus.nr = SENSORS_BUS_NR_ANY;
152 }
153
154 /* Last part is the chip address, or "*" for any address. */
155 if (!strcmp(name, "*")) {
156 res->addr = SENSORS_CHIP_NAME_ADDR_ANY;
157 } else {
158 res->addr = strtoul(name, &dash, 16);
159 if (*name == '\0' || *dash != '\0' || res->addr < 0)
160 goto ERROR;
161 }
162
163 return 0;
164
165ERROR:
166 free(res->prefix);
167 return -SENSORS_ERR_CHIP_NAME;
168}
169
170int sensors_snprintf_chip_name(char *str, size_t size,
171 const sensors_chip_name *chip)
172{
173 if (sensors_chip_name_has_wildcards(chip))
174 return -SENSORS_ERR_WILDCARDS;
175
176 switch (chip->bus.type) {
177 case SENSORS_BUS_TYPE_ISA:
178 return snprintf(str, size, "%s-isa-%04x", chip->prefix,
179 chip->addr);
180 case SENSORS_BUS_TYPE_PCI:
181 return snprintf(str, size, "%s-pci-%04x", chip->prefix,
182 chip->addr);
183 case SENSORS_BUS_TYPE_I2C:
184 return snprintf(str, size, "%s-i2c-%hd-%02x", chip->prefix,
185 chip->bus.nr, chip->addr);
186 case SENSORS_BUS_TYPE_SPI:
187 return snprintf(str, size, "%s-spi-%hd-%x", chip->prefix,
188 chip->bus.nr, chip->addr);
189 case SENSORS_BUS_TYPE_VIRTUAL:
190 return snprintf(str, size, "%s-virtual-%x", chip->prefix,
191 chip->addr);
192 case SENSORS_BUS_TYPE_ACPI:
193 return snprintf(str, size, "%s-acpi-%x", chip->prefix,
194 chip->addr);
195 case SENSORS_BUS_TYPE_HID:
196 return snprintf(str, size, "%s-hid-%hd-%x", chip->prefix,
197 chip->bus.nr, chip->addr);
198 }
199
200 return -SENSORS_ERR_CHIP_NAME;
201}
202
203int sensors_parse_bus_id(const char *name, sensors_bus_id *bus)
204{
205 char *endptr;
206
207 if (strncmp(name, "i2c-", 4)) {
208 return -SENSORS_ERR_BUS_NAME;
209 }
210 name += 4;
211 bus->type = SENSORS_BUS_TYPE_I2C;
212 bus->nr = strtoul(name, &endptr, 10);
213 if (*name == '\0' || *endptr != '\0' || bus->nr < 0)
214 return -SENSORS_ERR_BUS_NAME;
215 return 0;
216}
217
218static int sensors_substitute_chip(sensors_chip_name *name,
219 const char *filename, int lineno)
220{
221 int i, j;
222 for (i = 0; i < sensors_config_busses_count; i++)
223 if (sensors_config_busses[i].bus.type == name->bus.type &&
224 sensors_config_busses[i].bus.nr == name->bus.nr)
225 break;
226
227 if (i == sensors_config_busses_count) {
228 sensors_parse_error_wfn("Undeclared bus id referenced",
229 filename, lineno);
230 name->bus.nr = SENSORS_BUS_NR_IGNORE;
231 return -SENSORS_ERR_BUS_NAME;
232 }
233
234 /* Compare the adapter names */
235 for (j = 0; j < sensors_proc_bus_count; j++) {
236 if (!strcmp(sensors_config_busses[i].adapter,
237 sensors_proc_bus[j].adapter)) {
238 name->bus.nr = sensors_proc_bus[j].bus.nr;
239 return 0;
240 }
241 }
242
243 /* We did not find a matching bus name, simply ignore this chip
244 config entry. */
245 name->bus.nr = SENSORS_BUS_NR_IGNORE;
246 return 0;
247}
248
249/* Bus substitution is on a per-configuration file basis, so we keep
250 memory (in sensors_config_chips_subst) of which chip entries have been
251 already substituted. */
252int sensors_substitute_busses(void)
253{
254 int err, i, j, lineno;
255 sensors_chip_name_list *chips;
256 const char *filename;
257 int res = 0;
258
259 for (i = sensors_config_chips_subst;
260 i < sensors_config_chips_count; i++) {
261 filename = sensors_config_chips[i].line.filename;
262 lineno = sensors_config_chips[i].line.lineno;
263 chips = &sensors_config_chips[i].chips;
264 for (j = 0; j < chips->fits_count; j++) {
265 /* We can only substitute if a specific bus number
266 is given. */
267 if (chips->fits[j].bus.nr == SENSORS_BUS_NR_ANY)
268 continue;
269
270 err = sensors_substitute_chip(&chips->fits[j],
271 filename, lineno);
272 if (err)
273 res = err;
274 }
275 }
276 sensors_config_chips_subst = sensors_config_chips_count;
277 return res;
278}
diff --git a/tools/gator/daemon/libsensors/data.h b/tools/gator/daemon/libsensors/data.h
new file mode 100644
index 00000000000..4a23eabe141
--- /dev/null
+++ b/tools/gator/daemon/libsensors/data.h
@@ -0,0 +1,184 @@
1/*
2 data.h - Part of libsensors, a Linux library for reading sensor data.
3 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
4 Copyright (C) 2007, 2009 Jean Delvare <khali@linux-fr.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301 USA.
20*/
21
22#ifndef LIB_SENSORS_DATA_H
23#define LIB_SENSORS_DATA_H
24
25#include "sensors.h"
26#include "general.h"
27
28/* This header file contains all kinds of data structures which are used
29 for the representation of the config file data and the sensors
30 data. */
31
32/* Kinds of expression operators recognized */
33typedef enum sensors_operation {
34 sensors_add, sensors_sub, sensors_multiply, sensors_divide,
35 sensors_negate, sensors_exp, sensors_log,
36} sensors_operation;
37
38/* An expression can have several forms */
39typedef enum sensors_expr_kind {
40 sensors_kind_val, sensors_kind_source, sensors_kind_var,
41 sensors_kind_sub
42} sensors_expr_kind;
43
44/* An expression. It is either a floating point value, a variable name,
45 an operation on subexpressions, or the special value 'sub' } */
46struct sensors_expr;
47
48typedef struct sensors_subexpr {
49 sensors_operation op;
50 struct sensors_expr *sub1;
51 struct sensors_expr *sub2;
52} sensors_subexpr;
53
54typedef struct sensors_expr {
55 sensors_expr_kind kind;
56 union {
57 double val;
58 char *var;
59 sensors_subexpr subexpr;
60 } data;
61} sensors_expr;
62
63/* Config file line reference */
64typedef struct sensors_config_line {
65 const char *filename;
66 int lineno;
67} sensors_config_line;
68
69/* Config file label declaration: a feature name, combined with the label
70 value */
71typedef struct sensors_label {
72 char *name;
73 char *value;
74 sensors_config_line line;
75} sensors_label;
76
77/* Config file set declaration: a subfeature name, combined with an
78 expression */
79typedef struct sensors_set {
80 char *name;
81 sensors_expr *value;
82 sensors_config_line line;
83} sensors_set;
84
85/* Config file compute declaration: a feature name, combined with two
86 expressions */
87typedef struct sensors_compute {
88 char *name;
89 sensors_expr *from_proc;
90 sensors_expr *to_proc;
91 sensors_config_line line;
92} sensors_compute;
93
94/* Config file ignore declaration: a feature name */
95typedef struct sensors_ignore {
96 char *name;
97 sensors_config_line line;
98} sensors_ignore;
99
100/* A list of chip names, used to represent a config file chips declaration */
101typedef struct sensors_chip_name_list {
102 sensors_chip_name *fits;
103 int fits_count;
104 int fits_max;
105} sensors_chip_name_list;
106
107/* A config file chip block */
108typedef struct sensors_chip {
109 sensors_chip_name_list chips;
110 sensors_label *labels;
111 int labels_count;
112 int labels_max;
113 sensors_set *sets;
114 int sets_count;
115 int sets_max;
116 sensors_compute *computes;
117 int computes_count;
118 int computes_max;
119 sensors_ignore *ignores;
120 int ignores_count;
121 int ignores_max;
122 sensors_config_line line;
123} sensors_chip;
124
125/* Config file bus declaration: the bus type and number, combined with adapter
126 name */
127typedef struct sensors_bus {
128 char *adapter;
129 sensors_bus_id bus;
130 sensors_config_line line;
131} sensors_bus;
132
133/* Internal data about all features and subfeatures of a chip */
134typedef struct sensors_chip_features {
135 struct sensors_chip_name chip;
136 struct sensors_feature *feature;
137 struct sensors_subfeature *subfeature;
138 int feature_count;
139 int subfeature_count;
140} sensors_chip_features;
141
142extern char **sensors_config_files;
143extern int sensors_config_files_count;
144extern int sensors_config_files_max;
145
146#define sensors_add_config_files(el) sensors_add_array_el( \
147 (el), &sensors_config_files, &sensors_config_files_count, \
148 &sensors_config_files_max, sizeof(char *))
149
150extern sensors_chip *sensors_config_chips;
151extern int sensors_config_chips_count;
152extern int sensors_config_chips_subst;
153extern int sensors_config_chips_max;
154
155extern sensors_bus *sensors_config_busses;
156extern int sensors_config_busses_count;
157extern int sensors_config_busses_max;
158
159extern sensors_chip_features *sensors_proc_chips;
160extern int sensors_proc_chips_count;
161extern int sensors_proc_chips_max;
162
163#define sensors_add_proc_chips(el) sensors_add_array_el( \
164 (el), &sensors_proc_chips, &sensors_proc_chips_count,\
165 &sensors_proc_chips_max, sizeof(struct sensors_chip_features))
166
167extern sensors_bus *sensors_proc_bus;
168extern int sensors_proc_bus_count;
169extern int sensors_proc_bus_max;
170
171#define sensors_add_proc_bus(el) sensors_add_array_el( \
172 (el), &sensors_proc_bus, &sensors_proc_bus_count,\
173 &sensors_proc_bus_max, sizeof(struct sensors_bus))
174
175/* Substitute configuration bus numbers with real-world bus numbers
176 in the chips lists */
177int sensors_substitute_busses(void);
178
179
180/* Parse a bus id into its components. Returns 0 on success, a value from
181 error.h on failure. */
182int sensors_parse_bus_id(const char *name, sensors_bus_id *bus);
183
184#endif /* def LIB_SENSORS_DATA_H */
diff --git a/tools/gator/daemon/libsensors/error.c b/tools/gator/daemon/libsensors/error.c
new file mode 100644
index 00000000000..55bde81295f
--- /dev/null
+++ b/tools/gator/daemon/libsensors/error.c
@@ -0,0 +1,92 @@
1/*
2 error.c - Part of libsensors, a Linux library for reading sensor data.
3 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
4 Copyright (C) 2007-2009 Jean Delvare <khali@linux-fr.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301 USA.
20*/
21
22#include <stdlib.h>
23#include <stdio.h>
24#include "error.h"
25#include "general.h"
26
27static void sensors_default_parse_error(const char *err, int lineno);
28static void sensors_default_parse_error_wfn(const char *err,
29 const char *filename, int lineno);
30static void sensors_default_fatal_error(const char *proc, const char *err);
31
32void (*sensors_parse_error) (const char *err, int lineno) =
33 sensors_default_parse_error;
34void (*sensors_parse_error_wfn) (const char *err, const char *filename,
35 int lineno) = sensors_default_parse_error_wfn;
36void (*sensors_fatal_error) (const char *proc, const char *err) =
37 sensors_default_fatal_error;
38
39static const char *errorlist[] = {
40 /* Invalid error code */ "Unknown error",
41 /* SENSORS_ERR_WILDCARDS */ "Wildcard found in chip name",
42 /* SENSORS_ERR_NO_ENTRY */ "No such subfeature known",
43 /* SENSORS_ERR_ACCESS_R */ "Can't read",
44 /* SENSORS_ERR_KERNEL */ "Kernel interface error",
45 /* SENSORS_ERR_DIV_ZERO */ "Divide by zero",
46 /* SENSORS_ERR_CHIP_NAME */ "Can't parse chip name",
47 /* SENSORS_ERR_BUS_NAME */ "Can't parse bus name",
48 /* SENSORS_ERR_PARSE */ "General parse error",
49 /* SENSORS_ERR_ACCESS_W */ "Can't write",
50 /* SENSORS_ERR_IO */ "I/O error",
51 /* SENSORS_ERR_RECURSION */ "Evaluation recurses too deep",
52};
53
54const char *sensors_strerror(int errnum)
55{
56 if (errnum < 0)
57 errnum = -errnum;
58 if (errnum >= ARRAY_SIZE(errorlist))
59 errnum = 0;
60 return errorlist[errnum];
61}
62
63void sensors_default_parse_error(const char *err, int lineno)
64{
65 if (lineno)
66 fprintf(stderr, "Error: Line %d: %s\n", lineno, err);
67 else
68 fprintf(stderr, "Error: %s\n", err);
69}
70
71void sensors_default_parse_error_wfn(const char *err,
72 const char *filename, int lineno)
73{
74 /* If application provided a custom parse error reporting function
75 but not the variant with the filename, fall back to the original
76 variant without the filename, for backwards compatibility. */
77 if (sensors_parse_error != sensors_default_parse_error ||
78 !filename)
79 return sensors_parse_error(err, lineno);
80
81 if (lineno)
82 fprintf(stderr, "Error: File %s, line %d: %s\n", filename,
83 lineno, err);
84 else
85 fprintf(stderr, "Error: File %s: %s\n", filename, err);
86}
87
88void sensors_default_fatal_error(const char *proc, const char *err)
89{
90 fprintf(stderr, "Fatal error in `%s': %s\n", proc, err);
91 exit(1);
92}
diff --git a/tools/gator/daemon/libsensors/error.h b/tools/gator/daemon/libsensors/error.h
new file mode 100644
index 00000000000..37cdc956151
--- /dev/null
+++ b/tools/gator/daemon/libsensors/error.h
@@ -0,0 +1,74 @@
1/*
2 error.h - Part of libsensors, a Linux library for reading sensor data.
3 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
4 Copyright (C) 2007-2009 Jean Delvare <khali@linux-fr.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301 USA.
20*/
21
22#ifndef LIB_SENSORS_ERROR_H
23#define LIB_SENSORS_ERROR_H
24
25#define SENSORS_ERR_WILDCARDS 1 /* Wildcard found in chip name */
26#define SENSORS_ERR_NO_ENTRY 2 /* No such subfeature known */
27#define SENSORS_ERR_ACCESS_R 3 /* Can't read */
28#define SENSORS_ERR_KERNEL 4 /* Kernel interface error */
29#define SENSORS_ERR_DIV_ZERO 5 /* Divide by zero */
30#define SENSORS_ERR_CHIP_NAME 6 /* Can't parse chip name */
31#define SENSORS_ERR_BUS_NAME 7 /* Can't parse bus name */
32#define SENSORS_ERR_PARSE 8 /* General parse error */
33#define SENSORS_ERR_ACCESS_W 9 /* Can't write */
34#define SENSORS_ERR_IO 10 /* I/O error */
35#define SENSORS_ERR_RECURSION 11 /* Evaluation recurses too deep */
36
37#ifdef __cplusplus
38extern "C" {
39#endif /* __cplusplus */
40
41
42/* This function returns a pointer to a string which describes the error.
43 errnum may be negative (the corresponding positive error is returned).
44 You may not modify the result! */
45const char *sensors_strerror(int errnum);
46
47/* These functions are called when a parse error is detected. Give them new
48 values, and your own functions are called instead of the default (which
49 print to stderr). These functions may terminate the program, but they
50 usually output an error and return. The first function is the original
51 one, the second one was added later when support for multiple
52 configuration files was added.
53 The library code now only calls the second function. However, for
54 backwards compatibility, if an application provides a custom handling
55 function for the first function but not the second, then all parse
56 errors will be reported using the first function (that is, the filename
57 is never reported.)
58 Note that filename can be NULL (if filename isn't known) and lineno
59 can be 0 (if the error occurs before the actual parsing starts.) */
60extern void (*sensors_parse_error) (const char *err, int lineno);
61extern void (*sensors_parse_error_wfn) (const char *err,
62 const char *filename, int lineno);
63
64/* This function is called when an immediately fatal error (like no
65 memory left) is detected. Give it a new value, and your own function
66 is called instead of the default (which prints to stderr and ends
67 the program). Never let it return! */
68extern void (*sensors_fatal_error) (const char *proc, const char *err);
69
70#ifdef __cplusplus
71}
72#endif /* __cplusplus */
73
74#endif /* def LIB_SENSORS_ERROR_H */
diff --git a/tools/gator/daemon/libsensors/general.c b/tools/gator/daemon/libsensors/general.c
new file mode 100644
index 00000000000..f237e3b59c2
--- /dev/null
+++ b/tools/gator/daemon/libsensors/general.c
@@ -0,0 +1,85 @@
1/*
2 general.c - Part of libsensors, a Linux library for reading sensor data.
3 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 MA 02110-1301 USA.
19*/
20
21#include "error.h"
22#include "general.h"
23#include <errno.h>
24#include <stdio.h>
25#include <string.h>
26#include <stdlib.h>
27
28
29#define A_BUNCH 16
30
31void sensors_malloc_array(void *list, int *num_el, int *max_el, int el_size)
32{
33 void **my_list = (void **)list;
34
35 *my_list = malloc(el_size*A_BUNCH);
36 if (! *my_list)
37 sensors_fatal_error(__func__, "Allocating new elements");
38 *max_el = A_BUNCH;
39 *num_el = 0;
40}
41
42void sensors_free_array(void *list, int *num_el, int *max_el)
43{
44 void **my_list = (void **)list;
45
46 free(*my_list);
47 *my_list = NULL;
48 *num_el = 0;
49 *max_el = 0;
50}
51
52void sensors_add_array_el(const void *el, void *list, int *num_el,
53 int *max_el, int el_size)
54{
55 int new_max_el;
56 void **my_list = (void *)list;
57 if (*num_el + 1 > *max_el) {
58 new_max_el = *max_el + A_BUNCH;
59 *my_list = realloc(*my_list, new_max_el * el_size);
60 if (! *my_list)
61 sensors_fatal_error(__func__,
62 "Allocating new elements");
63 *max_el = new_max_el;
64 }
65 memcpy(((char *) *my_list) + *num_el * el_size, el, el_size);
66 (*num_el) ++;
67}
68
69void sensors_add_array_els(const void *els, int nr_els, void *list,
70 int *num_el, int *max_el, int el_size)
71{
72 int new_max_el;
73 void **my_list = (void *)list;
74 if (*num_el + nr_els > *max_el) {
75 new_max_el = (*max_el + nr_els + A_BUNCH);
76 new_max_el -= new_max_el % A_BUNCH;
77 *my_list = realloc(*my_list, new_max_el * el_size);
78 if (! *my_list)
79 sensors_fatal_error(__func__,
80 "Allocating new elements");
81 *max_el = new_max_el;
82 }
83 memcpy(((char *)*my_list) + *num_el * el_size, els, el_size * nr_els);
84 *num_el += nr_els;
85}
diff --git a/tools/gator/daemon/libsensors/general.h b/tools/gator/daemon/libsensors/general.h
new file mode 100644
index 00000000000..a3971e02e1b
--- /dev/null
+++ b/tools/gator/daemon/libsensors/general.h
@@ -0,0 +1,39 @@
1/*
2 general.h - Part of libsensors, a Linux library for reading sensor data.
3 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 MA 02110-1301 USA.
19*/
20
21#ifndef LIB_SENSORS_GENERAL
22#define LIB_SENSORS_GENERAL
23
24/* These are general purpose functions. They allow you to use variable-
25 length arrays, which are extended automatically. A distinction is
26 made between the current number of elements and the maximum number.
27 You can only add elements at the end. Primitive, but very useful
28 for internal use. */
29void sensors_malloc_array(void *list, int *num_el, int *max_el,
30 int el_size);
31void sensors_free_array(void *list, int *num_el, int *max_el);
32void sensors_add_array_el(const void *el, void *list, int *num_el,
33 int *max_el, int el_size);
34void sensors_add_array_els(const void *els, int nr_els, void *list,
35 int *num_el, int *max_el, int el_size);
36
37#define ARRAY_SIZE(arr) (int)(sizeof(arr) / sizeof((arr)[0]))
38
39#endif /* LIB_SENSORS_GENERAL */
diff --git a/tools/gator/daemon/libsensors/init.c b/tools/gator/daemon/libsensors/init.c
new file mode 100644
index 00000000000..558046e76c2
--- /dev/null
+++ b/tools/gator/daemon/libsensors/init.c
@@ -0,0 +1,341 @@
1/*
2 init.c - Part of libsensors, a Linux library for reading sensor data.
3 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
4 Copyright (C) 2007, 2009 Jean Delvare <khali@linux-fr.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301 USA.
20*/
21
22/*** This file modified by ARM on Jan 23, 2013 to cast alphasort to supress a warning as it's prototype is different on android. ***/
23
24/* Needed for scandir() and alphasort() */
25#define _BSD_SOURCE
26
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <locale.h>
30#include <stdlib.h>
31#include <stdio.h>
32#include <string.h>
33#include <errno.h>
34#include <dirent.h>
35#include <unistd.h>
36#include "sensors.h"
37#include "data.h"
38#include "error.h"
39#include "access.h"
40#include "conf.h"
41#include "sysfs.h"
42#include "scanner.h"
43#include "init.h"
44
45#define DEFAULT_CONFIG_FILE ETCDIR "/sensors3.conf"
46#define ALT_CONFIG_FILE ETCDIR "/sensors.conf"
47#define DEFAULT_CONFIG_DIR ETCDIR "/sensors.d"
48
49/* Wrapper around sensors_yyparse(), which clears the locale so that
50 the decimal numbers are always parsed properly. */
51static int sensors_parse(void)
52{
53 int res;
54 char *locale;
55
56 /* Remember the current locale and clear it */
57 locale = setlocale(LC_ALL, NULL);
58 if (locale) {
59 locale = strdup(locale);
60 if (!locale)
61 sensors_fatal_error(__func__, "Out of memory");
62
63 setlocale(LC_ALL, "C");
64 }
65
66 res = sensors_yyparse();
67
68 /* Restore the old locale */
69 if (locale) {
70 setlocale(LC_ALL, locale);
71 free(locale);
72 }
73
74 return res;
75}
76
77static void free_bus(sensors_bus *bus)
78{
79 free(bus->adapter);
80}
81
82static void free_config_busses(void)
83{
84 int i;
85
86 for (i = 0; i < sensors_config_busses_count; i++)
87 free_bus(&sensors_config_busses[i]);
88 free(sensors_config_busses);
89 sensors_config_busses = NULL;
90 sensors_config_busses_count = sensors_config_busses_max = 0;
91}
92
93static int parse_config(FILE *input, const char *name)
94{
95 int err;
96 char *name_copy;
97
98 if (name) {
99 /* Record configuration file name for error reporting */
100 name_copy = strdup(name);
101 if (!name_copy)
102 sensors_fatal_error(__func__, "Out of memory");
103 sensors_add_config_files(&name_copy);
104 } else
105 name_copy = NULL;
106
107 if (sensors_scanner_init(input, name_copy)) {
108 err = -SENSORS_ERR_PARSE;
109 goto exit_cleanup;
110 }
111 err = sensors_parse();
112 sensors_scanner_exit();
113 if (err) {
114 err = -SENSORS_ERR_PARSE;
115 goto exit_cleanup;
116 }
117
118 err = sensors_substitute_busses();
119
120exit_cleanup:
121 free_config_busses();
122 return err;
123}
124
125static int config_file_filter(const struct dirent *entry)
126{
127 return entry->d_name[0] != '.'; /* Skip hidden files */
128}
129
130static int add_config_from_dir(const char *dir)
131{
132 int count, res, i;
133 struct dirent **namelist;
134
135 count = scandir(dir, &namelist, config_file_filter, (int (*)(const struct dirent **, const struct dirent **))alphasort);
136 if (count < 0) {
137 /* Do not return an error if directory does not exist */
138 if (errno == ENOENT)
139 return 0;
140
141 sensors_parse_error_wfn(strerror(errno), NULL, 0);
142 return -SENSORS_ERR_PARSE;
143 }
144
145 for (res = 0, i = 0; !res && i < count; i++) {
146 int len;
147 char path[PATH_MAX];
148 FILE *input;
149 struct stat st;
150
151 len = snprintf(path, sizeof(path), "%s/%s", dir,
152 namelist[i]->d_name);
153 if (len < 0 || len >= (int)sizeof(path)) {
154 res = -SENSORS_ERR_PARSE;
155 continue;
156 }
157
158 /* Only accept regular files */
159 if (stat(path, &st) < 0 || !S_ISREG(st.st_mode))
160 continue;
161
162 input = fopen(path, "r");
163 if (input) {
164 res = parse_config(input, path);
165 fclose(input);
166 } else {
167 res = -SENSORS_ERR_PARSE;
168 sensors_parse_error_wfn(strerror(errno), path, 0);
169 }
170 }
171
172 /* Free memory allocated by scandir() */
173 for (i = 0; i < count; i++)
174 free(namelist[i]);
175 free(namelist);
176
177 return res;
178}
179
180int sensors_init(FILE *input)
181{
182 int res;
183
184 if (!sensors_init_sysfs())
185 return -SENSORS_ERR_KERNEL;
186 if ((res = sensors_read_sysfs_bus()) ||
187 (res = sensors_read_sysfs_chips()))
188 goto exit_cleanup;
189
190 if (input) {
191 res = parse_config(input, NULL);
192 if (res)
193 goto exit_cleanup;
194 } else {
195 const char* name;
196
197 /* No configuration provided, use default */
198 input = fopen(name = DEFAULT_CONFIG_FILE, "r");
199 if (!input && errno == ENOENT)
200 input = fopen(name = ALT_CONFIG_FILE, "r");
201 if (input) {
202 res = parse_config(input, name);
203 fclose(input);
204 if (res)
205 goto exit_cleanup;
206
207 } else if (errno != ENOENT) {
208 sensors_parse_error_wfn(strerror(errno), name, 0);
209 res = -SENSORS_ERR_PARSE;
210 goto exit_cleanup;
211 }
212
213 /* Also check for files in default directory */
214 res = add_config_from_dir(DEFAULT_CONFIG_DIR);
215 if (res)
216 goto exit_cleanup;
217 }
218
219 return 0;
220
221exit_cleanup:
222 sensors_cleanup();
223 return res;
224}
225
226static void free_chip_name(sensors_chip_name *name)
227{
228 free(name->prefix);
229 free(name->path);
230}
231
232static void free_chip_features(sensors_chip_features *features)
233{
234 int i;
235
236 for (i = 0; i < features->subfeature_count; i++)
237 free(features->subfeature[i].name);
238 free(features->subfeature);
239 for (i = 0; i < features->feature_count; i++)
240 free(features->feature[i].name);
241 free(features->feature);
242}
243
244static void free_label(sensors_label *label)
245{
246 free(label->name);
247 free(label->value);
248}
249
250void sensors_free_expr(sensors_expr *expr)
251{
252 if (expr->kind == sensors_kind_var)
253 free(expr->data.var);
254 else if (expr->kind == sensors_kind_sub) {
255 if (expr->data.subexpr.sub1)
256 sensors_free_expr(expr->data.subexpr.sub1);
257 if (expr->data.subexpr.sub2)
258 sensors_free_expr(expr->data.subexpr.sub2);
259 }
260 free(expr);
261}
262
263static void free_set(sensors_set *set)
264{
265 free(set->name);
266 sensors_free_expr(set->value);
267}
268
269static void free_compute(sensors_compute *compute)
270{
271 free(compute->name);
272 sensors_free_expr(compute->from_proc);
273 sensors_free_expr(compute->to_proc);
274}
275
276static void free_ignore(sensors_ignore *ignore)
277{
278 free(ignore->name);
279}
280
281static void free_chip(sensors_chip *chip)
282{
283 int i;
284
285 for (i = 0; i < chip->chips.fits_count; i++)
286 free_chip_name(&chip->chips.fits[i]);
287 free(chip->chips.fits);
288 chip->chips.fits_count = chip->chips.fits_max = 0;
289
290 for (i = 0; i < chip->labels_count; i++)
291 free_label(&chip->labels[i]);
292 free(chip->labels);
293 chip->labels_count = chip->labels_max = 0;
294
295 for (i = 0; i < chip->sets_count; i++)
296 free_set(&chip->sets[i]);
297 free(chip->sets);
298 chip->sets_count = chip->sets_max = 0;
299
300 for (i = 0; i < chip->computes_count; i++)
301 free_compute(&chip->computes[i]);
302 free(chip->computes);
303 chip->computes_count = chip->computes_max = 0;
304
305 for (i = 0; i < chip->ignores_count; i++)
306 free_ignore(&chip->ignores[i]);
307 free(chip->ignores);
308 chip->ignores_count = chip->ignores_max = 0;
309}
310
311void sensors_cleanup(void)
312{
313 int i;
314
315 for (i = 0; i < sensors_proc_chips_count; i++) {
316 free_chip_name(&sensors_proc_chips[i].chip);
317 free_chip_features(&sensors_proc_chips[i]);
318 }
319 free(sensors_proc_chips);
320 sensors_proc_chips = NULL;
321 sensors_proc_chips_count = sensors_proc_chips_max = 0;
322
323 for (i = 0; i < sensors_config_chips_count; i++)
324 free_chip(&sensors_config_chips[i]);
325 free(sensors_config_chips);
326 sensors_config_chips = NULL;
327 sensors_config_chips_count = sensors_config_chips_max = 0;
328 sensors_config_chips_subst = 0;
329
330 for (i = 0; i < sensors_proc_bus_count; i++)
331 free_bus(&sensors_proc_bus[i]);
332 free(sensors_proc_bus);
333 sensors_proc_bus = NULL;
334 sensors_proc_bus_count = sensors_proc_bus_max = 0;
335
336 for (i = 0; i < sensors_config_files_count; i++)
337 free(sensors_config_files[i]);
338 free(sensors_config_files);
339 sensors_config_files = NULL;
340 sensors_config_files_count = sensors_config_files_max = 0;
341}
diff --git a/tools/gator/daemon/libsensors/init.h b/tools/gator/daemon/libsensors/init.h
new file mode 100644
index 00000000000..47006a62db6
--- /dev/null
+++ b/tools/gator/daemon/libsensors/init.h
@@ -0,0 +1,28 @@
1/*
2 init.h - Part of libsensors, a Linux library for reading sensor data.
3 Copyright (C) 2007 Jean Delvare <khali@linux-fr.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 MA 02110-1301 USA.
19*/
20
21#ifndef LIB_SENSORS_INIT_H
22#define LIB_SENSORS_INIT_H
23
24#include "data.h"
25
26void sensors_free_expr(sensors_expr *expr);
27
28#endif /* def LIB_SENSORS_INIT_H */
diff --git a/tools/gator/daemon/libsensors/scanner.h b/tools/gator/daemon/libsensors/scanner.h
new file mode 100644
index 00000000000..4c415167de5
--- /dev/null
+++ b/tools/gator/daemon/libsensors/scanner.h
@@ -0,0 +1,32 @@
1/*
2 scanner.h - Part of libsensors, a Linux library for reading sensor data.
3 Copyright (c) 2006 Mark M. Hoffman <mhoffman@lightlink.com>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 MA 02110-1301 USA.
19*/
20
21/*** This file modified by ARM on Jan 23, 2013 to fix input defined but not used warning from conf-lex.c. ***/
22
23#ifndef LIB_SENSORS_SCANNER_H
24#define LIB_SENSORS_SCANNER_H
25
26int sensors_scanner_init(FILE *input, const char *filename);
27void sensors_scanner_exit(void);
28
29#define YY_NO_INPUT
30
31#endif
32
diff --git a/tools/gator/daemon/libsensors/sensors.h b/tools/gator/daemon/libsensors/sensors.h
new file mode 100644
index 00000000000..7874d028dc8
--- /dev/null
+++ b/tools/gator/daemon/libsensors/sensors.h
@@ -0,0 +1,311 @@
1/*
2 sensors.h - Part of libsensors, a Linux library for reading sensor data.
3 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
4 Copyright (C) 2007, 2010 Jean Delvare <khali@linux-fr.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301 USA.
20*/
21
22/*** This file modified by ARM on Jan 23, 2013 to read non-scaled values. ***/
23
24#ifndef LIB_SENSORS_SENSORS_H
25#define LIB_SENSORS_SENSORS_H
26
27#include <stdio.h>
28#include <limits.h>
29
30/* Publicly accessible library functions */
31
32/* libsensors API version define, first digit is the major version (changed
33 when the API + ABI breaks), the third digit is incremented to track small
34 API additions like new flags / enum values. The second digit is for tracking
35 larger additions like new methods. */
36#define SENSORS_API_VERSION 0x432
37
38#define SENSORS_CHIP_NAME_PREFIX_ANY NULL
39#define SENSORS_CHIP_NAME_ADDR_ANY (-1)
40
41#define SENSORS_BUS_TYPE_ANY (-1)
42#define SENSORS_BUS_TYPE_I2C 0
43#define SENSORS_BUS_TYPE_ISA 1
44#define SENSORS_BUS_TYPE_PCI 2
45#define SENSORS_BUS_TYPE_SPI 3
46#define SENSORS_BUS_TYPE_VIRTUAL 4
47#define SENSORS_BUS_TYPE_ACPI 5
48#define SENSORS_BUS_TYPE_HID 6
49#define SENSORS_BUS_NR_ANY (-1)
50#define SENSORS_BUS_NR_IGNORE (-2)
51
52#ifdef __cplusplus
53extern "C" {
54#endif /* __cplusplus */
55
56extern const char *libsensors_version;
57
58extern int sensors_sysfs_no_scaling;
59
60typedef struct sensors_bus_id {
61 short type;
62 short nr;
63} sensors_bus_id;
64
65/* A chip name is encoded in this structure */
66typedef struct sensors_chip_name {
67 char *prefix;
68 sensors_bus_id bus;
69 int addr;
70 char *path;
71} sensors_chip_name;
72
73/* Load the configuration file and the detected chips list. If this
74 returns a value unequal to zero, you are in trouble; you can not
75 assume anything will be initialized properly. If you want to
76 reload the configuration file, call sensors_cleanup() below before
77 calling sensors_init() again. */
78int sensors_init(FILE *input);
79
80/* Clean-up function: You can't access anything after
81 this, until the next sensors_init() call! */
82void sensors_cleanup(void);
83
84/* Parse a chip name to the internal representation. Return 0 on success, <0
85 on error. */
86int sensors_parse_chip_name(const char *orig_name, sensors_chip_name *res);
87
88/* Free memory allocated for the internal representation of a chip name. */
89void sensors_free_chip_name(sensors_chip_name *chip);
90
91/* Print a chip name from its internal representation. Note that chip should
92 not contain wildcard values! Return the number of characters printed on
93 success (same as snprintf), <0 on error. */
94int sensors_snprintf_chip_name(char *str, size_t size,
95 const sensors_chip_name *chip);
96
97/* This function returns the adapter name of a bus,
98 as used within the sensors_chip_name structure. If it could not be found,
99 it returns NULL */
100const char *sensors_get_adapter_name(const sensors_bus_id *bus);
101
102typedef struct sensors_feature sensors_feature;
103
104/* Look up the label for a given feature. Note that chip should not
105 contain wildcard values! The returned string is newly allocated (free it
106 yourself). On failure, NULL is returned.
107 If no label exists for this feature, its name is returned itself. */
108char *sensors_get_label(const sensors_chip_name *name,
109 const sensors_feature *feature);
110
111/* Read the value of a subfeature of a certain chip. Note that chip should not
112 contain wildcard values! This function will return 0 on success, and <0
113 on failure. */
114int sensors_get_value(const sensors_chip_name *name, int subfeat_nr,
115 double *value);
116
117/* Set the value of a subfeature of a certain chip. Note that chip should not
118 contain wildcard values! This function will return 0 on success, and <0
119 on failure. */
120int sensors_set_value(const sensors_chip_name *name, int subfeat_nr,
121 double value);
122
123/* Execute all set statements for this particular chip. The chip may contain
124 wildcards! This function will return 0 on success, and <0 on failure. */
125int sensors_do_chip_sets(const sensors_chip_name *name);
126
127/* This function returns all detected chips that match a given chip name,
128 one by one. If no chip name is provided, all detected chips are returned.
129 To start at the beginning of the list, use 0 for nr; NULL is returned if
130 we are at the end of the list. Do not try to change these chip names, as
131 they point to internal structures! */
132const sensors_chip_name *sensors_get_detected_chips(const sensors_chip_name
133 *match, int *nr);
134
135/* These defines are used in the flags field of sensors_subfeature */
136#define SENSORS_MODE_R 1
137#define SENSORS_MODE_W 2
138#define SENSORS_COMPUTE_MAPPING 4
139
140typedef enum sensors_feature_type {
141 SENSORS_FEATURE_IN = 0x00,
142 SENSORS_FEATURE_FAN = 0x01,
143 SENSORS_FEATURE_TEMP = 0x02,
144 SENSORS_FEATURE_POWER = 0x03,
145 SENSORS_FEATURE_ENERGY = 0x04,
146 SENSORS_FEATURE_CURR = 0x05,
147 SENSORS_FEATURE_HUMIDITY = 0x06,
148 SENSORS_FEATURE_MAX_MAIN,
149 SENSORS_FEATURE_VID = 0x10,
150 SENSORS_FEATURE_INTRUSION = 0x11,
151 SENSORS_FEATURE_MAX_OTHER,
152 SENSORS_FEATURE_BEEP_ENABLE = 0x18,
153 SENSORS_FEATURE_UNKNOWN = INT_MAX,
154} sensors_feature_type;
155
156/* All the sensor types (in, fan, temp, vid) are a multiple of 0x100 apart,
157 and sensor subfeatures which have no compute mapping have bit 7 set. */
158typedef enum sensors_subfeature_type {
159 SENSORS_SUBFEATURE_IN_INPUT = SENSORS_FEATURE_IN << 8,
160 SENSORS_SUBFEATURE_IN_MIN,
161 SENSORS_SUBFEATURE_IN_MAX,
162 SENSORS_SUBFEATURE_IN_LCRIT,
163 SENSORS_SUBFEATURE_IN_CRIT,
164 SENSORS_SUBFEATURE_IN_AVERAGE,
165 SENSORS_SUBFEATURE_IN_LOWEST,
166 SENSORS_SUBFEATURE_IN_HIGHEST,
167 SENSORS_SUBFEATURE_IN_ALARM = (SENSORS_FEATURE_IN << 8) | 0x80,
168 SENSORS_SUBFEATURE_IN_MIN_ALARM,
169 SENSORS_SUBFEATURE_IN_MAX_ALARM,
170 SENSORS_SUBFEATURE_IN_BEEP,
171 SENSORS_SUBFEATURE_IN_LCRIT_ALARM,
172 SENSORS_SUBFEATURE_IN_CRIT_ALARM,
173
174 SENSORS_SUBFEATURE_FAN_INPUT = SENSORS_FEATURE_FAN << 8,
175 SENSORS_SUBFEATURE_FAN_MIN,
176 SENSORS_SUBFEATURE_FAN_MAX,
177 SENSORS_SUBFEATURE_FAN_ALARM = (SENSORS_FEATURE_FAN << 8) | 0x80,
178 SENSORS_SUBFEATURE_FAN_FAULT,
179 SENSORS_SUBFEATURE_FAN_DIV,
180 SENSORS_SUBFEATURE_FAN_BEEP,
181 SENSORS_SUBFEATURE_FAN_PULSES,
182 SENSORS_SUBFEATURE_FAN_MIN_ALARM,
183 SENSORS_SUBFEATURE_FAN_MAX_ALARM,
184
185 SENSORS_SUBFEATURE_TEMP_INPUT = SENSORS_FEATURE_TEMP << 8,
186 SENSORS_SUBFEATURE_TEMP_MAX,
187 SENSORS_SUBFEATURE_TEMP_MAX_HYST,
188 SENSORS_SUBFEATURE_TEMP_MIN,
189 SENSORS_SUBFEATURE_TEMP_CRIT,
190 SENSORS_SUBFEATURE_TEMP_CRIT_HYST,
191 SENSORS_SUBFEATURE_TEMP_LCRIT,
192 SENSORS_SUBFEATURE_TEMP_EMERGENCY,
193 SENSORS_SUBFEATURE_TEMP_EMERGENCY_HYST,
194 SENSORS_SUBFEATURE_TEMP_LOWEST,
195 SENSORS_SUBFEATURE_TEMP_HIGHEST,
196 SENSORS_SUBFEATURE_TEMP_ALARM = (SENSORS_FEATURE_TEMP << 8) | 0x80,
197 SENSORS_SUBFEATURE_TEMP_MAX_ALARM,
198 SENSORS_SUBFEATURE_TEMP_MIN_ALARM,
199 SENSORS_SUBFEATURE_TEMP_CRIT_ALARM,
200 SENSORS_SUBFEATURE_TEMP_FAULT,
201 SENSORS_SUBFEATURE_TEMP_TYPE,
202 SENSORS_SUBFEATURE_TEMP_OFFSET,
203 SENSORS_SUBFEATURE_TEMP_BEEP,
204 SENSORS_SUBFEATURE_TEMP_EMERGENCY_ALARM,
205 SENSORS_SUBFEATURE_TEMP_LCRIT_ALARM,
206
207 SENSORS_SUBFEATURE_POWER_AVERAGE = SENSORS_FEATURE_POWER << 8,
208 SENSORS_SUBFEATURE_POWER_AVERAGE_HIGHEST,
209 SENSORS_SUBFEATURE_POWER_AVERAGE_LOWEST,
210 SENSORS_SUBFEATURE_POWER_INPUT,
211 SENSORS_SUBFEATURE_POWER_INPUT_HIGHEST,
212 SENSORS_SUBFEATURE_POWER_INPUT_LOWEST,
213 SENSORS_SUBFEATURE_POWER_CAP,
214 SENSORS_SUBFEATURE_POWER_CAP_HYST,
215 SENSORS_SUBFEATURE_POWER_MAX,
216 SENSORS_SUBFEATURE_POWER_CRIT,
217 SENSORS_SUBFEATURE_POWER_AVERAGE_INTERVAL = (SENSORS_FEATURE_POWER << 8) | 0x80,
218 SENSORS_SUBFEATURE_POWER_ALARM,
219 SENSORS_SUBFEATURE_POWER_CAP_ALARM,
220 SENSORS_SUBFEATURE_POWER_MAX_ALARM,
221 SENSORS_SUBFEATURE_POWER_CRIT_ALARM,
222
223 SENSORS_SUBFEATURE_ENERGY_INPUT = SENSORS_FEATURE_ENERGY << 8,
224
225 SENSORS_SUBFEATURE_CURR_INPUT = SENSORS_FEATURE_CURR << 8,
226 SENSORS_SUBFEATURE_CURR_MIN,
227 SENSORS_SUBFEATURE_CURR_MAX,
228 SENSORS_SUBFEATURE_CURR_LCRIT,
229 SENSORS_SUBFEATURE_CURR_CRIT,
230 SENSORS_SUBFEATURE_CURR_AVERAGE,
231 SENSORS_SUBFEATURE_CURR_LOWEST,
232 SENSORS_SUBFEATURE_CURR_HIGHEST,
233 SENSORS_SUBFEATURE_CURR_ALARM = (SENSORS_FEATURE_CURR << 8) | 0x80,
234 SENSORS_SUBFEATURE_CURR_MIN_ALARM,
235 SENSORS_SUBFEATURE_CURR_MAX_ALARM,
236 SENSORS_SUBFEATURE_CURR_BEEP,
237 SENSORS_SUBFEATURE_CURR_LCRIT_ALARM,
238 SENSORS_SUBFEATURE_CURR_CRIT_ALARM,
239
240 SENSORS_SUBFEATURE_HUMIDITY_INPUT = SENSORS_FEATURE_HUMIDITY << 8,
241
242 SENSORS_SUBFEATURE_VID = SENSORS_FEATURE_VID << 8,
243
244 SENSORS_SUBFEATURE_INTRUSION_ALARM = SENSORS_FEATURE_INTRUSION << 8,
245 SENSORS_SUBFEATURE_INTRUSION_BEEP,
246
247 SENSORS_SUBFEATURE_BEEP_ENABLE = SENSORS_FEATURE_BEEP_ENABLE << 8,
248
249 SENSORS_SUBFEATURE_UNKNOWN = INT_MAX,
250} sensors_subfeature_type;
251
252/* Data about a single chip feature (or category leader) */
253struct sensors_feature {
254 char *name;
255 int number;
256 sensors_feature_type type;
257 /* Members below are for libsensors internal use only */
258 int first_subfeature;
259 int padding1;
260};
261
262/* Data about a single chip subfeature:
263 name is the string name used to refer to this subfeature (in config files)
264 number is the internal subfeature number, used in many functions to refer
265 to this subfeature
266 type is the subfeature type
267 mapping is the number of a main feature this subfeature belongs to
268 (for example subfeatures fan1_input, fan1_min, fan1_div and fan1_alarm
269 are mapped to main feature fan1)
270 flags is a bitfield, its value is a combination of SENSORS_MODE_R (readable),
271 SENSORS_MODE_W (writable) and SENSORS_COMPUTE_MAPPING (affected by the
272 computation rules of the main feature) */
273typedef struct sensors_subfeature {
274 char *name;
275 int number;
276 sensors_subfeature_type type;
277 int mapping;
278 unsigned int flags;
279} sensors_subfeature;
280
281/* This returns all main features of a specific chip. nr is an internally
282 used variable. Set it to zero to start at the begin of the list. If no
283 more features are found NULL is returned.
284 Do not try to change the returned structure; you will corrupt internal
285 data structures. */
286const sensors_feature *
287sensors_get_features(const sensors_chip_name *name, int *nr);
288
289/* This returns all subfeatures of a given main feature. nr is an internally
290 used variable. Set it to zero to start at the begin of the list. If no
291 more features are found NULL is returned.
292 Do not try to change the returned structure; you will corrupt internal
293 data structures. */
294const sensors_subfeature *
295sensors_get_all_subfeatures(const sensors_chip_name *name,
296 const sensors_feature *feature, int *nr);
297
298/* This returns the subfeature of the given type for a given main feature,
299 if it exists, NULL otherwise.
300 Do not try to change the returned structure; you will corrupt internal
301 data structures. */
302const sensors_subfeature *
303sensors_get_subfeature(const sensors_chip_name *name,
304 const sensors_feature *feature,
305 sensors_subfeature_type type);
306
307#ifdef __cplusplus
308}
309#endif /* __cplusplus */
310
311#endif /* def LIB_SENSORS_ERROR_H */
diff --git a/tools/gator/daemon/libsensors/sysfs.c b/tools/gator/daemon/libsensors/sysfs.c
new file mode 100644
index 00000000000..2b494c9975b
--- /dev/null
+++ b/tools/gator/daemon/libsensors/sysfs.c
@@ -0,0 +1,926 @@
1/*
2 sysfs.c - Part of libsensors, a library for reading Linux sensor data
3 Copyright (c) 2005 Mark M. Hoffman <mhoffman@lightlink.com>
4 Copyright (C) 2007-2010 Jean Delvare <khali@linux-fr.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301 USA.
20*/
21
22/*** This file modified by ARM on Jan 23, 2013 to improve performance by substituting calls to fread() with calls to read() and to read non-scaled values. ***/
23
24/* this define needed for strndup() */
25#define _GNU_SOURCE
26
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <sys/vfs.h>
30#include <unistd.h>
31#include <string.h>
32#include <stdlib.h>
33#include <limits.h>
34#include <errno.h>
35#include <dirent.h>
36#include <fcntl.h>
37#include "data.h"
38#include "error.h"
39#include "access.h"
40#include "general.h"
41#include "sysfs.h"
42
43
44/****************************************************************************/
45
46#define ATTR_MAX 128
47#define SYSFS_MAGIC 0x62656572
48
49int sensors_sysfs_no_scaling;
50
51/*
52 * Read an attribute from sysfs
53 * Returns a pointer to a freshly allocated string; free it yourself.
54 * If the file doesn't exist or can't be read, NULL is returned.
55 */
56static char *sysfs_read_attr(const char *device, const char *attr)
57{
58 char path[NAME_MAX];
59 char buf[ATTR_MAX], *p;
60 FILE *f;
61
62 snprintf(path, NAME_MAX, "%s/%s", device, attr);
63
64 if (!(f = fopen(path, "r")))
65 return NULL;
66 p = fgets(buf, ATTR_MAX, f);
67 fclose(f);
68 if (!p)
69 return NULL;
70
71 /* Last byte is a '\n'; chop that off */
72 p = strndup(buf, strlen(buf) - 1);
73 if (!p)
74 sensors_fatal_error(__func__, "Out of memory");
75 return p;
76}
77
78/*
79 * Call an arbitrary function for each class device of the given class
80 * Returns 0 on success (all calls returned 0), a positive errno for
81 * local errors, or a negative error value if any call fails.
82 */
83static int sysfs_foreach_classdev(const char *class_name,
84 int (*func)(const char *, const char *))
85{
86 char path[NAME_MAX];
87 int path_off, ret;
88 DIR *dir;
89 struct dirent *ent;
90
91 path_off = snprintf(path, NAME_MAX, "%s/class/%s",
92 sensors_sysfs_mount, class_name);
93 if (!(dir = opendir(path)))
94 return errno;
95
96 ret = 0;
97 while (!ret && (ent = readdir(dir))) {
98 if (ent->d_name[0] == '.') /* skip hidden entries */
99 continue;
100
101 snprintf(path + path_off, NAME_MAX - path_off, "/%s",
102 ent->d_name);
103 ret = func(path, ent->d_name);
104 }
105
106 closedir(dir);
107 return ret;
108}
109
110/*
111 * Call an arbitrary function for each device of the given bus type
112 * Returns 0 on success (all calls returned 0), a positive errno for
113 * local errors, or a negative error value if any call fails.
114 */
115static int sysfs_foreach_busdev(const char *bus_type,
116 int (*func)(const char *, const char *))
117{
118 char path[NAME_MAX];
119 int path_off, ret;
120 DIR *dir;
121 struct dirent *ent;
122
123 path_off = snprintf(path, NAME_MAX, "%s/bus/%s/devices",
124 sensors_sysfs_mount, bus_type);
125 if (!(dir = opendir(path)))
126 return errno;
127
128 ret = 0;
129 while (!ret && (ent = readdir(dir))) {
130 if (ent->d_name[0] == '.') /* skip hidden entries */
131 continue;
132
133 snprintf(path + path_off, NAME_MAX - path_off, "/%s",
134 ent->d_name);
135 ret = func(path, ent->d_name);
136 }
137
138 closedir(dir);
139 return ret;
140}
141
142/****************************************************************************/
143
144char sensors_sysfs_mount[NAME_MAX];
145
146#define MAX_MAIN_SENSOR_TYPES (SENSORS_FEATURE_MAX_MAIN - SENSORS_FEATURE_IN)
147#define MAX_OTHER_SENSOR_TYPES (SENSORS_FEATURE_MAX_OTHER - SENSORS_FEATURE_VID)
148#define MAX_SENSORS_PER_TYPE 24
149/* max_subfeatures is now computed dynamically */
150#define FEATURE_SIZE (max_subfeatures * 2)
151#define FEATURE_TYPE_SIZE (MAX_SENSORS_PER_TYPE * FEATURE_SIZE)
152
153/*
154 * Room for all 7 main types (in, fan, temp, power, energy, current, humidity)
155 * and 2 other types (VID, intrusion) with all their subfeatures + misc features
156 */
157#define SUB_OFFSET_OTHER (MAX_MAIN_SENSOR_TYPES * FEATURE_TYPE_SIZE)
158#define SUB_OFFSET_MISC (SUB_OFFSET_OTHER + \
159 MAX_OTHER_SENSOR_TYPES * FEATURE_TYPE_SIZE)
160#define ALL_POSSIBLE_SUBFEATURES (SUB_OFFSET_MISC + 1)
161
162static
163int get_type_scaling(sensors_subfeature_type type)
164{
165 /* Multipliers for subfeatures */
166 switch (type & 0xFF80) {
167 case SENSORS_SUBFEATURE_IN_INPUT:
168 case SENSORS_SUBFEATURE_TEMP_INPUT:
169 case SENSORS_SUBFEATURE_CURR_INPUT:
170 case SENSORS_SUBFEATURE_HUMIDITY_INPUT:
171 return 1000;
172 case SENSORS_SUBFEATURE_FAN_INPUT:
173 return 1;
174 case SENSORS_SUBFEATURE_POWER_AVERAGE:
175 case SENSORS_SUBFEATURE_ENERGY_INPUT:
176 return 1000000;
177 }
178
179 /* Multipliers for second class subfeatures
180 that need their own multiplier */
181 switch (type) {
182 case SENSORS_SUBFEATURE_POWER_AVERAGE_INTERVAL:
183 case SENSORS_SUBFEATURE_VID:
184 case SENSORS_SUBFEATURE_TEMP_OFFSET:
185 return 1000;
186 default:
187 return 1;
188 }
189}
190
191static
192char *get_feature_name(sensors_feature_type ftype, char *sfname)
193{
194 char *name, *underscore;
195
196 switch (ftype) {
197 case SENSORS_FEATURE_IN:
198 case SENSORS_FEATURE_FAN:
199 case SENSORS_FEATURE_TEMP:
200 case SENSORS_FEATURE_POWER:
201 case SENSORS_FEATURE_ENERGY:
202 case SENSORS_FEATURE_CURR:
203 case SENSORS_FEATURE_HUMIDITY:
204 case SENSORS_FEATURE_INTRUSION:
205 underscore = strchr(sfname, '_');
206 name = strndup(sfname, underscore - sfname);
207 if (!name)
208 sensors_fatal_error(__func__, "Out of memory");
209
210 break;
211 default:
212 name = strdup(sfname);
213 if (!name)
214 sensors_fatal_error(__func__, "Out of memory");
215 }
216
217 return name;
218}
219
220/* Static mappings for use by sensors_subfeature_get_type() */
221struct subfeature_type_match
222{
223 const char *name;
224 sensors_subfeature_type type;
225};
226
227struct feature_type_match
228{
229 const char *name;
230 const struct subfeature_type_match *submatches;
231};
232
233static const struct subfeature_type_match temp_matches[] = {
234 { "input", SENSORS_SUBFEATURE_TEMP_INPUT },
235 { "max", SENSORS_SUBFEATURE_TEMP_MAX },
236 { "max_hyst", SENSORS_SUBFEATURE_TEMP_MAX_HYST },
237 { "min", SENSORS_SUBFEATURE_TEMP_MIN },
238 { "crit", SENSORS_SUBFEATURE_TEMP_CRIT },
239 { "crit_hyst", SENSORS_SUBFEATURE_TEMP_CRIT_HYST },
240 { "lcrit", SENSORS_SUBFEATURE_TEMP_LCRIT },
241 { "emergency", SENSORS_SUBFEATURE_TEMP_EMERGENCY },
242 { "emergency_hyst", SENSORS_SUBFEATURE_TEMP_EMERGENCY_HYST },
243 { "lowest", SENSORS_SUBFEATURE_TEMP_LOWEST },
244 { "highest", SENSORS_SUBFEATURE_TEMP_HIGHEST },
245 { "alarm", SENSORS_SUBFEATURE_TEMP_ALARM },
246 { "min_alarm", SENSORS_SUBFEATURE_TEMP_MIN_ALARM },
247 { "max_alarm", SENSORS_SUBFEATURE_TEMP_MAX_ALARM },
248 { "crit_alarm", SENSORS_SUBFEATURE_TEMP_CRIT_ALARM },
249 { "emergency_alarm", SENSORS_SUBFEATURE_TEMP_EMERGENCY_ALARM },
250 { "lcrit_alarm", SENSORS_SUBFEATURE_TEMP_LCRIT_ALARM },
251 { "fault", SENSORS_SUBFEATURE_TEMP_FAULT },
252 { "type", SENSORS_SUBFEATURE_TEMP_TYPE },
253 { "offset", SENSORS_SUBFEATURE_TEMP_OFFSET },
254 { "beep", SENSORS_SUBFEATURE_TEMP_BEEP },
255 { NULL, 0 }
256};
257
258static const struct subfeature_type_match in_matches[] = {
259 { "input", SENSORS_SUBFEATURE_IN_INPUT },
260 { "min", SENSORS_SUBFEATURE_IN_MIN },
261 { "max", SENSORS_SUBFEATURE_IN_MAX },
262 { "lcrit", SENSORS_SUBFEATURE_IN_LCRIT },
263 { "crit", SENSORS_SUBFEATURE_IN_CRIT },
264 { "average", SENSORS_SUBFEATURE_IN_AVERAGE },
265 { "lowest", SENSORS_SUBFEATURE_IN_LOWEST },
266 { "highest", SENSORS_SUBFEATURE_IN_HIGHEST },
267 { "alarm", SENSORS_SUBFEATURE_IN_ALARM },
268 { "min_alarm", SENSORS_SUBFEATURE_IN_MIN_ALARM },
269 { "max_alarm", SENSORS_SUBFEATURE_IN_MAX_ALARM },
270 { "lcrit_alarm", SENSORS_SUBFEATURE_IN_LCRIT_ALARM },
271 { "crit_alarm", SENSORS_SUBFEATURE_IN_CRIT_ALARM },
272 { "beep", SENSORS_SUBFEATURE_IN_BEEP },
273 { NULL, 0 }
274};
275
276static const struct subfeature_type_match fan_matches[] = {
277 { "input", SENSORS_SUBFEATURE_FAN_INPUT },
278 { "min", SENSORS_SUBFEATURE_FAN_MIN },
279 { "max", SENSORS_SUBFEATURE_FAN_MAX },
280 { "div", SENSORS_SUBFEATURE_FAN_DIV },
281 { "pulses", SENSORS_SUBFEATURE_FAN_PULSES },
282 { "alarm", SENSORS_SUBFEATURE_FAN_ALARM },
283 { "min_alarm", SENSORS_SUBFEATURE_FAN_MIN_ALARM },
284 { "max_alarm", SENSORS_SUBFEATURE_FAN_MAX_ALARM },
285 { "fault", SENSORS_SUBFEATURE_FAN_FAULT },
286 { "beep", SENSORS_SUBFEATURE_FAN_BEEP },
287 { NULL, 0 }
288};
289
290static const struct subfeature_type_match power_matches[] = {
291 { "average", SENSORS_SUBFEATURE_POWER_AVERAGE },
292 { "average_highest", SENSORS_SUBFEATURE_POWER_AVERAGE_HIGHEST },
293 { "average_lowest", SENSORS_SUBFEATURE_POWER_AVERAGE_LOWEST },
294 { "input", SENSORS_SUBFEATURE_POWER_INPUT },
295 { "input_highest", SENSORS_SUBFEATURE_POWER_INPUT_HIGHEST },
296 { "input_lowest", SENSORS_SUBFEATURE_POWER_INPUT_LOWEST },
297 { "cap", SENSORS_SUBFEATURE_POWER_CAP },
298 { "cap_hyst", SENSORS_SUBFEATURE_POWER_CAP_HYST },
299 { "cap_alarm", SENSORS_SUBFEATURE_POWER_CAP_ALARM },
300 { "alarm", SENSORS_SUBFEATURE_POWER_ALARM },
301 { "max", SENSORS_SUBFEATURE_POWER_MAX },
302 { "max_alarm", SENSORS_SUBFEATURE_POWER_MAX_ALARM },
303 { "crit", SENSORS_SUBFEATURE_POWER_CRIT },
304 { "crit_alarm", SENSORS_SUBFEATURE_POWER_CRIT_ALARM },
305 { "average_interval", SENSORS_SUBFEATURE_POWER_AVERAGE_INTERVAL },
306 { NULL, 0 }
307};
308
309static const struct subfeature_type_match energy_matches[] = {
310 { "input", SENSORS_SUBFEATURE_ENERGY_INPUT },
311 { NULL, 0 }
312};
313
314static const struct subfeature_type_match curr_matches[] = {
315 { "input", SENSORS_SUBFEATURE_CURR_INPUT },
316 { "min", SENSORS_SUBFEATURE_CURR_MIN },
317 { "max", SENSORS_SUBFEATURE_CURR_MAX },
318 { "lcrit", SENSORS_SUBFEATURE_CURR_LCRIT },
319 { "crit", SENSORS_SUBFEATURE_CURR_CRIT },
320 { "average", SENSORS_SUBFEATURE_CURR_AVERAGE },
321 { "lowest", SENSORS_SUBFEATURE_CURR_LOWEST },
322 { "highest", SENSORS_SUBFEATURE_CURR_HIGHEST },
323 { "alarm", SENSORS_SUBFEATURE_CURR_ALARM },
324 { "min_alarm", SENSORS_SUBFEATURE_CURR_MIN_ALARM },
325 { "max_alarm", SENSORS_SUBFEATURE_CURR_MAX_ALARM },
326 { "lcrit_alarm", SENSORS_SUBFEATURE_CURR_LCRIT_ALARM },
327 { "crit_alarm", SENSORS_SUBFEATURE_CURR_CRIT_ALARM },
328 { "beep", SENSORS_SUBFEATURE_CURR_BEEP },
329 { NULL, 0 }
330};
331
332static const struct subfeature_type_match humidity_matches[] = {
333 { "input", SENSORS_SUBFEATURE_HUMIDITY_INPUT },
334 { NULL, 0 }
335};
336
337static const struct subfeature_type_match cpu_matches[] = {
338 { "vid", SENSORS_SUBFEATURE_VID },
339 { NULL, 0 }
340};
341
342static const struct subfeature_type_match intrusion_matches[] = {
343 { "alarm", SENSORS_SUBFEATURE_INTRUSION_ALARM },
344 { "beep", SENSORS_SUBFEATURE_INTRUSION_BEEP },
345 { NULL, 0 }
346};
347static struct feature_type_match matches[] = {
348 { "temp%d%c", temp_matches },
349 { "in%d%c", in_matches },
350 { "fan%d%c", fan_matches },
351 { "cpu%d%c", cpu_matches },
352 { "power%d%c", power_matches },
353 { "curr%d%c", curr_matches },
354 { "energy%d%c", energy_matches },
355 { "intrusion%d%c", intrusion_matches },
356 { "humidity%d%c", humidity_matches },
357};
358
359/* Return the subfeature type and channel number based on the subfeature
360 name */
361static
362sensors_subfeature_type sensors_subfeature_get_type(const char *name, int *nr)
363{
364 char c;
365 int i, count;
366 const struct subfeature_type_match *submatches;
367
368 /* Special case */
369 if (!strcmp(name, "beep_enable")) {
370 *nr = 0;
371 return SENSORS_SUBFEATURE_BEEP_ENABLE;
372 }
373
374 for (i = 0; i < ARRAY_SIZE(matches); i++)
375 if ((count = sscanf(name, matches[i].name, nr, &c)))
376 break;
377
378 if (i == ARRAY_SIZE(matches) || count != 2 || c != '_')
379 return SENSORS_SUBFEATURE_UNKNOWN; /* no match */
380
381 submatches = matches[i].submatches;
382 name = strchr(name + 3, '_') + 1;
383 for (i = 0; submatches[i].name != NULL; i++)
384 if (!strcmp(name, submatches[i].name))
385 return submatches[i].type;
386
387 return SENSORS_SUBFEATURE_UNKNOWN;
388}
389
390static int sensors_compute_max(void)
391{
392 int i, j, max, offset;
393 const struct subfeature_type_match *submatches;
394 sensors_feature_type ftype;
395
396 max = 0;
397 for (i = 0; i < ARRAY_SIZE(matches); i++) {
398 submatches = matches[i].submatches;
399 for (j = 0; submatches[j].name != NULL; j++) {
400 ftype = submatches[j].type >> 8;
401
402 if (ftype < SENSORS_FEATURE_VID) {
403 offset = submatches[j].type & 0x7F;
404 if (offset >= max)
405 max = offset + 1;
406 } else {
407 offset = submatches[j].type & 0xFF;
408 if (offset >= max * 2)
409 max = ((offset + 1) + 1) / 2;
410 }
411 }
412 }
413
414 return max;
415}
416
417static int sensors_get_attr_mode(const char *device, const char *attr)
418{
419 char path[NAME_MAX];
420 struct stat st;
421 int mode = 0;
422
423 snprintf(path, NAME_MAX, "%s/%s", device, attr);
424 if (!stat(path, &st)) {
425 if (st.st_mode & S_IRUSR)
426 mode |= SENSORS_MODE_R;
427 if (st.st_mode & S_IWUSR)
428 mode |= SENSORS_MODE_W;
429 }
430 return mode;
431}
432
433static int sensors_read_dynamic_chip(sensors_chip_features *chip,
434 const char *dev_path)
435{
436 int i, fnum = 0, sfnum = 0, prev_slot;
437 static int max_subfeatures;
438 DIR *dir;
439 struct dirent *ent;
440 sensors_subfeature *all_subfeatures;
441 sensors_subfeature *dyn_subfeatures;
442 sensors_feature *dyn_features;
443 sensors_feature_type ftype;
444 sensors_subfeature_type sftype;
445
446 if (!(dir = opendir(dev_path)))
447 return -errno;
448
449 /* Dynamically figure out the max number of subfeatures */
450 if (!max_subfeatures)
451 max_subfeatures = sensors_compute_max();
452
453 /* We use a large sparse table at first to store all found
454 subfeatures, so that we can store them sorted at type and index
455 and then later create a dense sorted table. */
456 all_subfeatures = calloc(ALL_POSSIBLE_SUBFEATURES,
457 sizeof(sensors_subfeature));
458 if (!all_subfeatures)
459 sensors_fatal_error(__func__, "Out of memory");
460
461 while ((ent = readdir(dir))) {
462 char *name;
463 int nr;
464
465 /* Skip directories and symlinks */
466 if (ent->d_type != DT_REG)
467 continue;
468
469 name = ent->d_name;
470
471 sftype = sensors_subfeature_get_type(name, &nr);
472 if (sftype == SENSORS_SUBFEATURE_UNKNOWN)
473 continue;
474 ftype = sftype >> 8;
475
476 /* Adjust the channel number */
477 switch (ftype) {
478 case SENSORS_FEATURE_FAN:
479 case SENSORS_FEATURE_TEMP:
480 case SENSORS_FEATURE_POWER:
481 case SENSORS_FEATURE_ENERGY:
482 case SENSORS_FEATURE_CURR:
483 case SENSORS_FEATURE_HUMIDITY:
484 nr--;
485 break;
486 default:
487 break;
488 }
489
490 if (nr < 0 || nr >= MAX_SENSORS_PER_TYPE) {
491 /* More sensors of one type than MAX_SENSORS_PER_TYPE,
492 we have to ignore it */
493#ifdef DEBUG
494 sensors_fatal_error(__func__,
495 "Increase MAX_SENSORS_PER_TYPE!");
496#endif
497 continue;
498 }
499
500 /* "calculate" a place to store the subfeature in our sparse,
501 sorted table */
502 switch (ftype) {
503 case SENSORS_FEATURE_VID:
504 case SENSORS_FEATURE_INTRUSION:
505 i = SUB_OFFSET_OTHER +
506 (ftype - SENSORS_FEATURE_VID) * FEATURE_TYPE_SIZE +
507 nr * FEATURE_SIZE + (sftype & 0xFF);
508 break;
509 case SENSORS_FEATURE_BEEP_ENABLE:
510 i = SUB_OFFSET_MISC +
511 (ftype - SENSORS_FEATURE_BEEP_ENABLE);
512 break;
513 default:
514 i = ftype * FEATURE_TYPE_SIZE +
515 nr * FEATURE_SIZE +
516 ((sftype & 0x80) >> 7) * max_subfeatures +
517 (sftype & 0x7F);
518 }
519
520 if (all_subfeatures[i].name) {
521#ifdef DEBUG
522 sensors_fatal_error(__func__, "Duplicate subfeature");
523#endif
524 continue;
525 }
526
527 /* fill in the subfeature members */
528 all_subfeatures[i].type = sftype;
529 all_subfeatures[i].name = strdup(name);
530 if (!all_subfeatures[i].name)
531 sensors_fatal_error(__func__, "Out of memory");
532
533 /* Other and misc subfeatures are never scaled */
534 if (sftype < SENSORS_SUBFEATURE_VID && !(sftype & 0x80))
535 all_subfeatures[i].flags |= SENSORS_COMPUTE_MAPPING;
536 all_subfeatures[i].flags |= sensors_get_attr_mode(dev_path, name);
537
538 sfnum++;
539 }
540 closedir(dir);
541
542 if (!sfnum) { /* No subfeature */
543 chip->subfeature = NULL;
544 goto exit_free;
545 }
546
547 /* How many main features? */
548 prev_slot = -1;
549 for (i = 0; i < ALL_POSSIBLE_SUBFEATURES; i++) {
550 if (!all_subfeatures[i].name)
551 continue;
552
553 if (i >= SUB_OFFSET_MISC || i / FEATURE_SIZE != prev_slot) {
554 fnum++;
555 prev_slot = i / FEATURE_SIZE;
556 }
557 }
558
559 dyn_subfeatures = calloc(sfnum, sizeof(sensors_subfeature));
560 dyn_features = calloc(fnum, sizeof(sensors_feature));
561 if (!dyn_subfeatures || !dyn_features)
562 sensors_fatal_error(__func__, "Out of memory");
563
564 /* Copy from the sparse array to the compact array */
565 sfnum = 0;
566 fnum = -1;
567 prev_slot = -1;
568 for (i = 0; i < ALL_POSSIBLE_SUBFEATURES; i++) {
569 if (!all_subfeatures[i].name)
570 continue;
571
572 /* New main feature? */
573 if (i >= SUB_OFFSET_MISC || i / FEATURE_SIZE != prev_slot) {
574 ftype = all_subfeatures[i].type >> 8;
575 fnum++;
576 prev_slot = i / FEATURE_SIZE;
577
578 dyn_features[fnum].name = get_feature_name(ftype,
579 all_subfeatures[i].name);
580 dyn_features[fnum].number = fnum;
581 dyn_features[fnum].first_subfeature = sfnum;
582 dyn_features[fnum].type = ftype;
583 }
584
585 dyn_subfeatures[sfnum] = all_subfeatures[i];
586 dyn_subfeatures[sfnum].number = sfnum;
587 /* Back to the feature */
588 dyn_subfeatures[sfnum].mapping = fnum;
589
590 sfnum++;
591 }
592
593 chip->subfeature = dyn_subfeatures;
594 chip->subfeature_count = sfnum;
595 chip->feature = dyn_features;
596 chip->feature_count = ++fnum;
597
598exit_free:
599 free(all_subfeatures);
600 return 0;
601}
602
603/* returns !0 if sysfs filesystem was found, 0 otherwise */
604int sensors_init_sysfs(void)
605{
606 struct statfs statfsbuf;
607
608 snprintf(sensors_sysfs_mount, NAME_MAX, "%s", "/sys");
609 if (statfs(sensors_sysfs_mount, &statfsbuf) < 0
610 || statfsbuf.f_type != SYSFS_MAGIC)
611 return 0;
612
613 return 1;
614}
615
616/* returns: number of devices added (0 or 1) if successful, <0 otherwise */
617static int sensors_read_one_sysfs_chip(const char *dev_path,
618 const char *dev_name,
619 const char *hwmon_path)
620{
621 int domain, bus, slot, fn, vendor, product, id;
622 int err = -SENSORS_ERR_KERNEL;
623 char *bus_attr;
624 char bus_path[NAME_MAX];
625 char linkpath[NAME_MAX];
626 char subsys_path[NAME_MAX], *subsys;
627 int sub_len;
628 sensors_chip_features entry;
629
630 /* ignore any device without name attribute */
631 if (!(entry.chip.prefix = sysfs_read_attr(hwmon_path, "name")))
632 return 0;
633
634 entry.chip.path = strdup(hwmon_path);
635 if (!entry.chip.path)
636 sensors_fatal_error(__func__, "Out of memory");
637
638 if (dev_path == NULL) {
639 /* Virtual device */
640 entry.chip.bus.type = SENSORS_BUS_TYPE_VIRTUAL;
641 entry.chip.bus.nr = 0;
642 /* For now we assume that virtual devices are unique */
643 entry.chip.addr = 0;
644 goto done;
645 }
646
647 /* Find bus type */
648 snprintf(linkpath, NAME_MAX, "%s/subsystem", dev_path);
649 sub_len = readlink(linkpath, subsys_path, NAME_MAX - 1);
650 if (sub_len < 0 && errno == ENOENT) {
651 /* Fallback to "bus" link for kernels <= 2.6.17 */
652 snprintf(linkpath, NAME_MAX, "%s/bus", dev_path);
653 sub_len = readlink(linkpath, subsys_path, NAME_MAX - 1);
654 }
655 if (sub_len < 0) {
656 /* Older kernels (<= 2.6.11) have neither the subsystem
657 symlink nor the bus symlink */
658 if (errno == ENOENT)
659 subsys = NULL;
660 else
661 goto exit_free;
662 } else {
663 subsys_path[sub_len] = '\0';
664 subsys = strrchr(subsys_path, '/') + 1;
665 }
666
667 if ((!subsys || !strcmp(subsys, "i2c")) &&
668 sscanf(dev_name, "%hd-%x", &entry.chip.bus.nr,
669 &entry.chip.addr) == 2) {
670 /* find out if legacy ISA or not */
671 if (entry.chip.bus.nr == 9191) {
672 entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
673 entry.chip.bus.nr = 0;
674 } else {
675 entry.chip.bus.type = SENSORS_BUS_TYPE_I2C;
676 snprintf(bus_path, sizeof(bus_path),
677 "%s/class/i2c-adapter/i2c-%d/device",
678 sensors_sysfs_mount, entry.chip.bus.nr);
679
680 if ((bus_attr = sysfs_read_attr(bus_path, "name"))) {
681 if (!strncmp(bus_attr, "ISA ", 4)) {
682 entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
683 entry.chip.bus.nr = 0;
684 }
685
686 free(bus_attr);
687 }
688 }
689 } else
690 if ((!subsys || !strcmp(subsys, "spi")) &&
691 sscanf(dev_name, "spi%hd.%d", &entry.chip.bus.nr,
692 &entry.chip.addr) == 2) {
693 /* SPI */
694 entry.chip.bus.type = SENSORS_BUS_TYPE_SPI;
695 } else
696 if ((!subsys || !strcmp(subsys, "pci")) &&
697 sscanf(dev_name, "%x:%x:%x.%x", &domain, &bus, &slot, &fn) == 4) {
698 /* PCI */
699 entry.chip.addr = (domain << 16) + (bus << 8) + (slot << 3) + fn;
700 entry.chip.bus.type = SENSORS_BUS_TYPE_PCI;
701 entry.chip.bus.nr = 0;
702 } else
703 if ((!subsys || !strcmp(subsys, "platform") ||
704 !strcmp(subsys, "of_platform"))) {
705 /* must be new ISA (platform driver) */
706 if (sscanf(dev_name, "%*[a-z0-9_].%d", &entry.chip.addr) != 1)
707 entry.chip.addr = 0;
708 entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
709 entry.chip.bus.nr = 0;
710 } else if (subsys && !strcmp(subsys, "acpi")) {
711 entry.chip.bus.type = SENSORS_BUS_TYPE_ACPI;
712 /* For now we assume that acpi devices are unique */
713 entry.chip.bus.nr = 0;
714 entry.chip.addr = 0;
715 } else
716 if (subsys && !strcmp(subsys, "hid") &&
717 sscanf(dev_name, "%x:%x:%x.%x", &bus, &vendor, &product, &id) == 4) {
718 entry.chip.bus.type = SENSORS_BUS_TYPE_HID;
719 /* As of kernel 2.6.32, the hid device names don't look good */
720 entry.chip.bus.nr = bus;
721 entry.chip.addr = id;
722 } else {
723 /* Ignore unknown device */
724 err = 0;
725 goto exit_free;
726 }
727
728done:
729 if (sensors_read_dynamic_chip(&entry, hwmon_path) < 0)
730 goto exit_free;
731 if (!entry.subfeature) { /* No subfeature, discard chip */
732 err = 0;
733 goto exit_free;
734 }
735 sensors_add_proc_chips(&entry);
736
737 return 1;
738
739exit_free:
740 free(entry.chip.prefix);
741 free(entry.chip.path);
742 return err;
743}
744
745static int sensors_add_hwmon_device_compat(const char *path,
746 const char *dev_name)
747{
748 int err;
749
750 err = sensors_read_one_sysfs_chip(path, dev_name, path);
751 if (err < 0)
752 return err;
753 return 0;
754}
755
756/* returns 0 if successful, !0 otherwise */
757static int sensors_read_sysfs_chips_compat(void)
758{
759 int ret;
760
761 ret = sysfs_foreach_busdev("i2c", sensors_add_hwmon_device_compat);
762 if (ret && ret != ENOENT)
763 return -SENSORS_ERR_KERNEL;
764
765 return 0;
766}
767
768static int sensors_add_hwmon_device(const char *path, const char *classdev)
769{
770 char linkpath[NAME_MAX];
771 char device[NAME_MAX], *device_p;
772 int dev_len, err;
773 (void)classdev; /* hide warning */
774
775 snprintf(linkpath, NAME_MAX, "%s/device", path);
776 dev_len = readlink(linkpath, device, NAME_MAX - 1);
777 if (dev_len < 0) {
778 /* No device link? Treat as virtual */
779 err = sensors_read_one_sysfs_chip(NULL, NULL, path);
780 } else {
781 device[dev_len] = '\0';
782 device_p = strrchr(device, '/') + 1;
783
784 /* The attributes we want might be those of the hwmon class
785 device, or those of the device itself. */
786 err = sensors_read_one_sysfs_chip(linkpath, device_p, path);
787 if (err == 0)
788 err = sensors_read_one_sysfs_chip(linkpath, device_p,
789 linkpath);
790 }
791 if (err < 0)
792 return err;
793 return 0;
794}
795
796/* returns 0 if successful, !0 otherwise */
797int sensors_read_sysfs_chips(void)
798{
799 int ret;
800
801 ret = sysfs_foreach_classdev("hwmon", sensors_add_hwmon_device);
802 if (ret == ENOENT) {
803 /* compatibility function for kernel 2.6.n where n <= 13 */
804 return sensors_read_sysfs_chips_compat();
805 }
806
807 if (ret > 0)
808 ret = -SENSORS_ERR_KERNEL;
809 return ret;
810}
811
812/* returns 0 if successful, !0 otherwise */
813static int sensors_add_i2c_bus(const char *path, const char *classdev)
814{
815 sensors_bus entry;
816
817 if (sscanf(classdev, "i2c-%hd", &entry.bus.nr) != 1 ||
818 entry.bus.nr == 9191) /* legacy ISA */
819 return 0;
820 entry.bus.type = SENSORS_BUS_TYPE_I2C;
821
822 /* Get the adapter name from the classdev "name" attribute
823 * (Linux 2.6.20 and later). If it fails, fall back to
824 * the device "name" attribute (for older kernels). */
825 entry.adapter = sysfs_read_attr(path, "name");
826 if (!entry.adapter)
827 entry.adapter = sysfs_read_attr(path, "device/name");
828 if (entry.adapter)
829 sensors_add_proc_bus(&entry);
830
831 return 0;
832}
833
834/* returns 0 if successful, !0 otherwise */
835int sensors_read_sysfs_bus(void)
836{
837 int ret;
838
839 ret = sysfs_foreach_classdev("i2c-adapter", sensors_add_i2c_bus);
840 if (ret == ENOENT)
841 ret = sysfs_foreach_busdev("i2c", sensors_add_i2c_bus);
842 if (ret && ret != ENOENT)
843 return -SENSORS_ERR_KERNEL;
844
845 return 0;
846}
847
848int sensors_read_sysfs_attr(const sensors_chip_name *name,
849 const sensors_subfeature *subfeature,
850 double *value)
851{
852 char n[NAME_MAX];
853 int f;
854
855 snprintf(n, NAME_MAX, "%s/%s", name->path, subfeature->name);
856 if ((f = open(n, O_RDONLY)) != -1) {
857 int res, err = 0;
858 char buf[512];
859 int count;
860
861 errno = 0;
862 if ((count = read(f, buf, sizeof(buf) - 1)) == -1) {
863 if (errno == EIO)
864 err = -SENSORS_ERR_IO;
865 else
866 err = -SENSORS_ERR_ACCESS_R;
867 } else {
868 buf[count] = '\0';
869 errno = 0;
870 res = sscanf(buf, "%lf", value);
871 if (res == EOF && errno == EIO)
872 err = -SENSORS_ERR_IO;
873 else if (res != 1)
874 err = -SENSORS_ERR_ACCESS_R;
875 }
876 res = close(f);
877 if (err)
878 return err;
879
880 if (res != 0) {
881 if (errno == EIO)
882 return -SENSORS_ERR_IO;
883 else
884 return -SENSORS_ERR_ACCESS_R;
885 }
886 if (!sensors_sysfs_no_scaling)
887 *value /= get_type_scaling(subfeature->type);
888 } else
889 return -SENSORS_ERR_KERNEL;
890
891 return 0;
892}
893
894int sensors_write_sysfs_attr(const sensors_chip_name *name,
895 const sensors_subfeature *subfeature,
896 double value)
897{
898 char n[NAME_MAX];
899 FILE *f;
900
901 snprintf(n, NAME_MAX, "%s/%s", name->path, subfeature->name);
902 if ((f = fopen(n, "w"))) {
903 int res, err = 0;
904
905 if (!sensors_sysfs_no_scaling)
906 value *= get_type_scaling(subfeature->type);
907 res = fprintf(f, "%d", (int) value);
908 if (res == -EIO)
909 err = -SENSORS_ERR_IO;
910 else if (res < 0)
911 err = -SENSORS_ERR_ACCESS_W;
912 res = fclose(f);
913 if (err)
914 return err;
915
916 if (res == EOF) {
917 if (errno == EIO)
918 return -SENSORS_ERR_IO;
919 else
920 return -SENSORS_ERR_ACCESS_W;
921 }
922 } else
923 return -SENSORS_ERR_KERNEL;
924
925 return 0;
926}
diff --git a/tools/gator/daemon/libsensors/sysfs.h b/tools/gator/daemon/libsensors/sysfs.h
new file mode 100644
index 00000000000..38584afd028
--- /dev/null
+++ b/tools/gator/daemon/libsensors/sysfs.h
@@ -0,0 +1,43 @@
1/*
2 sysfs.h - part of libsensors, a library for reading Linux sensor data
3 Copyright (C) Mark M. Hoffman <mhoffman@lightlink.com>
4 Copyright (C) 2007 Jean Delvare <khali@linux-fr.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301 USA.
20*/
21
22#ifndef SENSORS_LIB_SYSFS_H
23#define SENSORS_LIB_SYSFS_H
24
25extern char sensors_sysfs_mount[];
26
27int sensors_init_sysfs(void);
28
29int sensors_read_sysfs_chips(void);
30
31int sensors_read_sysfs_bus(void);
32
33/* Read a value out of a sysfs attribute file */
34int sensors_read_sysfs_attr(const sensors_chip_name *name,
35 const sensors_subfeature *subfeature,
36 double *value);
37
38/* Write a value to a sysfs attribute file */
39int sensors_write_sysfs_attr(const sensors_chip_name *name,
40 const sensors_subfeature *subfeature,
41 double value);
42
43#endif /* !SENSORS_LIB_SYSFS_H */
diff --git a/tools/gator/daemon/libsensors/version.h b/tools/gator/daemon/libsensors/version.h
new file mode 100644
index 00000000000..76ceb08c29d
--- /dev/null
+++ b/tools/gator/daemon/libsensors/version.h
@@ -0,0 +1 @@
#define LM_VERSION "3.3.2"
diff --git a/tools/gator/daemon/main.cpp b/tools/gator/daemon/main.cpp
new file mode 100644
index 00000000000..2998c701222
--- /dev/null
+++ b/tools/gator/daemon/main.cpp
@@ -0,0 +1,547 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include <arpa/inet.h>
10#include <fcntl.h>
11#include <pthread.h>
12#include <sys/mman.h>
13#include <sys/mount.h>
14#include <sys/prctl.h>
15#include <sys/resource.h>
16#include <sys/socket.h>
17#include <sys/stat.h>
18#include <sys/syscall.h>
19#include <sys/wait.h>
20#include <unistd.h>
21
22#include "Child.h"
23#include "EventsXML.h"
24#include "KMod.h"
25#include "Logging.h"
26#include "Monitor.h"
27#include "OlySocket.h"
28#include "OlyUtility.h"
29#include "SessionData.h"
30
31#define DEBUG false
32
33extern Child* child;
34static int shutdownFilesystem();
35static pthread_mutex_t numSessions_mutex;
36static OlyServerSocket* sock = NULL;
37static Monitor monitor;
38static int numSessions = 0;
39static bool driverRunningAtStart = false;
40static bool driverMountedAtStart = false;
41
42struct cmdline_t {
43 int port;
44 char* module;
45};
46
47#define DEFAULT_PORT 8080
48
49void cleanUp() {
50 if (shutdownFilesystem() == -1) {
51 logg->logMessage("Error shutting down gator filesystem");
52 }
53 delete sock;
54 delete util;
55 delete logg;
56}
57
58// CTRL C Signal Handler
59static void handler(int signum) {
60 logg->logMessage("Received signal %d, gator daemon exiting", signum);
61
62 // Case 1: both child and parent receive the signal
63 if (numSessions > 0) {
64 // Arbitrary sleep of 1 second to give time for the child to exit;
65 // if something bad happens, continue the shutdown process regardless
66 sleep(1);
67 }
68
69 // Case 2: only the parent received the signal
70 if (numSessions > 0) {
71 // Kill child threads - the first signal exits gracefully
72 logg->logMessage("Killing process group as %d child was running when signal was received", numSessions);
73 kill(0, SIGINT);
74
75 // Give time for the child to exit
76 sleep(1);
77
78 if (numSessions > 0) {
79 // The second signal force kills the child
80 logg->logMessage("Force kill the child");
81 kill(0, SIGINT);
82 // Again, sleep for 1 second
83 sleep(1);
84
85 if (numSessions > 0) {
86 // Something bad has really happened; the child is not exiting and therefore may hold the /dev/gator resource open
87 printf("Unable to kill the gatord child process, thus gator.ko may still be loaded.\n");
88 }
89 }
90 }
91
92 cleanUp();
93 exit(0);
94}
95
96// Child exit Signal Handler
97static void child_exit(int) {
98 int status;
99 int pid = wait(&status);
100 if (pid != -1) {
101 pthread_mutex_lock(&numSessions_mutex);
102 numSessions--;
103 pthread_mutex_unlock(&numSessions_mutex);
104 logg->logMessage("Child process %d exited with status %d", pid, status);
105 }
106}
107
108static const int UDP_ANS_PORT = 30000;
109static const int UDP_REQ_PORT = 30001;
110
111typedef struct {
112 char rviHeader[8];
113 uint32_t messageID;
114 uint8_t ethernetAddress[8];
115 uint32_t ethernetType;
116 uint32_t dhcp;
117 char dhcpName[40];
118 uint32_t ipAddress;
119 uint32_t defaultGateway;
120 uint32_t subnetMask;
121 uint32_t activeConnections;
122} RVIConfigureInfo;
123
124static const char DST_REQ[] = { 'D', 'S', 'T', '_', 'R', 'E', 'Q', ' ', 0, 0, 0, 0x64 };
125
126class UdpListener {
127public:
128 UdpListener() : mDstAns(), mReq(-1), mAns(-1) {}
129
130 void setup(int port) {
131 mReq = udpPort(UDP_REQ_PORT);
132 mAns = udpPort(UDP_ANS_PORT);
133
134 // Format the answer buffer
135 memset(&mDstAns, 0, sizeof(mDstAns));
136 memcpy(mDstAns.rviHeader, "STR_ANS ", sizeof(mDstAns.rviHeader));
137 if (gethostname(mDstAns.dhcpName, sizeof(mDstAns.dhcpName) - 1) != 0) {
138 logg->logError(__FILE__, __LINE__, "gethostname failed");
139 handleException();
140 }
141 // Subvert the defaultGateway field for the port number
142 if (port != DEFAULT_PORT) {
143 mDstAns.defaultGateway = port;
144 }
145 // Subvert the subnetMask field for the protocol version
146 mDstAns.subnetMask = PROTOCOL_VERSION;
147 }
148
149 int getReq() const {
150 return mReq;
151 }
152
153 void handle() {
154 char buf[128];
155 struct sockaddr_in6 sockaddr;
156 socklen_t addrlen;
157 int read;
158 addrlen = sizeof(sockaddr);
159 read = recvfrom(mReq, &buf, sizeof(buf), 0, (struct sockaddr *)&sockaddr, &addrlen);
160 if (read < 0) {
161 logg->logError(__FILE__, __LINE__, "recvfrom failed");
162 handleException();
163 } else if ((read == 12) && (memcmp(buf, DST_REQ, sizeof(DST_REQ)) == 0)) {
164 if (sendto(mAns, &mDstAns, sizeof(mDstAns), 0, (struct sockaddr *)&sockaddr, addrlen) != sizeof(mDstAns)) {
165 logg->logError(__FILE__, __LINE__, "sendto failed");
166 handleException();
167 }
168 }
169 }
170
171 void close() {
172 ::close(mReq);
173 ::close(mAns);
174 }
175
176private:
177 int udpPort(int port) {
178 int s;
179 struct sockaddr_in6 sockaddr;
180 int on;
181 int family = AF_INET6;
182
183 s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
184 if (s == -1) {
185 family = AF_INET;
186 s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
187 if (s == -1) {
188 logg->logError(__FILE__, __LINE__, "socket failed");
189 handleException();
190 }
191 }
192
193 on = 1;
194 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)) != 0) {
195 logg->logError(__FILE__, __LINE__, "setsockopt failed");
196 handleException();
197 }
198
199 memset((void*)&sockaddr, 0, sizeof(sockaddr));
200 sockaddr.sin6_family = family;
201 sockaddr.sin6_port = htons(port);
202 sockaddr.sin6_addr = in6addr_any;
203 if (bind(s, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) {
204 logg->logError(__FILE__, __LINE__, "socket failed");
205 handleException();
206 }
207
208 return s;
209 }
210
211 RVIConfigureInfo mDstAns;
212 int mReq;
213 int mAns;
214};
215
216static UdpListener udpListener;
217
218// retval: -1 = failure; 0 = was already mounted; 1 = successfully mounted
219static int mountGatorFS() {
220 // If already mounted,
221 if (access("/dev/gator/buffer", F_OK) == 0) {
222 return 0;
223 }
224
225 // else, mount the filesystem
226 mkdir("/dev/gator", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
227 if (mount("nodev", "/dev/gator", "gatorfs", 0, NULL) != 0) {
228 return -1;
229 } else {
230 return 1;
231 }
232}
233
234static bool init_module (const char * const location) {
235 bool ret(false);
236 const int fd = open(location, O_RDONLY);
237 if (fd >= 0) {
238 struct stat st;
239 if (fstat(fd, &st) == 0) {
240 void * const p = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
241 if (p != MAP_FAILED) {
242 if (syscall(__NR_init_module, p, (unsigned long)st.st_size, "") == 0) {
243 ret = true;
244 }
245 munmap(p, st.st_size);
246 }
247 }
248 close(fd);
249 }
250
251 return ret;
252}
253
254static bool setupFilesystem(char* module) {
255 if (module) {
256 // unmount and rmmod if the module was specified on the commandline, i.e. ensure that the specified module is indeed running
257 shutdownFilesystem();
258
259 // if still mounted
260 if (access("/dev/gator/buffer", F_OK) == 0) {
261 logg->logError(__FILE__, __LINE__, "Unable to remove the running gator.ko. Manually remove the module or use the running module by not specifying one on the commandline");
262 handleException();
263 }
264 }
265
266 const int retval = mountGatorFS();
267 if (retval == 1) {
268 logg->logMessage("Driver already running at startup");
269 driverRunningAtStart = true;
270 } else if (retval == 0) {
271 logg->logMessage("Driver already mounted at startup");
272 driverRunningAtStart = driverMountedAtStart = true;
273 } else {
274 char command[256]; // arbitrarily large amount
275 char location[256]; // arbitrarily large amount
276
277 if (module) {
278 strncpy(location, module, sizeof(location));
279 } else {
280 // Is the driver co-located in the same directory?
281 if (util->getApplicationFullPath(location, sizeof(location)) != 0) { // allow some buffer space
282 logg->logMessage("Unable to determine the full path of gatord, the cwd will be used");
283 }
284 strncat(location, "gator.ko", sizeof(location) - strlen(location) - 1);
285 }
286
287 if (access(location, F_OK) == -1) {
288 if (module == NULL) {
289 // The gator kernel is not already loaded and unable to locate gator.ko in the default location
290 return false;
291 } else {
292 // gator location specified on the command line but it was not found
293 logg->logError(__FILE__, __LINE__, "gator module not found at %s", location);
294 handleException();
295 }
296 }
297
298 // Load driver
299 bool success = init_module(location);
300 if (!success) {
301 logg->logMessage("init_module failed, trying insmod");
302 snprintf(command, sizeof(command), "insmod %s >/dev/null 2>&1", location);
303 if (system(command) != 0) {
304 logg->logMessage("Unable to load gator.ko driver with command: %s", command);
305 logg->logError(__FILE__, __LINE__, "Unable to load (insmod) gator.ko driver:\n >>> gator.ko must be built against the current kernel version & configuration\n >>> See dmesg for more details");
306 handleException();
307 }
308 }
309
310 if (mountGatorFS() == -1) {
311 logg->logError(__FILE__, __LINE__, "Unable to mount the gator filesystem needed for profiling.");
312 handleException();
313 }
314 }
315
316 return true;
317}
318
319static int shutdownFilesystem() {
320 if (driverMountedAtStart == false) {
321 umount("/dev/gator");
322 }
323 if (driverRunningAtStart == false) {
324 if (syscall(__NR_delete_module, "gator", O_NONBLOCK) != 0) {
325 logg->logMessage("delete_module failed, trying rmmod");
326 if (system("rmmod gator >/dev/null 2>&1") != 0) {
327 return -1;
328 }
329 }
330 }
331
332 return 0; // success
333}
334
335static struct cmdline_t parseCommandLine(int argc, char** argv) {
336 struct cmdline_t cmdline;
337 cmdline.port = DEFAULT_PORT;
338 cmdline.module = NULL;
339 char version_string[256]; // arbitrary length to hold the version information
340 int c;
341
342 // build the version string
343 if (PROTOCOL_VERSION < PROTOCOL_DEV) {
344 snprintf(version_string, sizeof(version_string), "Streamline gatord version %d (DS-5 v5.%d)", PROTOCOL_VERSION, PROTOCOL_VERSION);
345 } else {
346 snprintf(version_string, sizeof(version_string), "Streamline gatord development version %d", PROTOCOL_VERSION);
347 }
348
349 while ((c = getopt(argc, argv, "hvp:s:c:e:m:o:")) != -1) {
350 switch(c) {
351 case 'c':
352 gSessionData->mConfigurationXMLPath = optarg;
353 break;
354 case 'e':
355 gSessionData->mEventsXMLPath = optarg;
356 break;
357 case 'm':
358 cmdline.module = optarg;
359 break;
360 case 'p':
361 cmdline.port = strtol(optarg, NULL, 10);
362 break;
363 case 's':
364 gSessionData->mSessionXMLPath = optarg;
365 break;
366 case 'o':
367 gSessionData->mTargetPath = optarg;
368 break;
369 case 'h':
370 case '?':
371 logg->logError(__FILE__, __LINE__,
372 "%s. All parameters are optional:\n"
373 "-c config_xml path and filename of the configuration.xml to use\n"
374 "-e events_xml path and filename of the events.xml to use\n"
375 "-h this help page\n"
376 "-m module path and filename of gator.ko\n"
377 "-p port_number port upon which the server listens; default is 8080\n"
378 "-s session_xml path and filename of a session xml used for local capture\n"
379 "-o apc_dir path and name of the output for a local capture\n"
380 "-v version information\n"
381 , version_string);
382 handleException();
383 break;
384 case 'v':
385 logg->logError(__FILE__, __LINE__, version_string);
386 handleException();
387 break;
388 }
389 }
390
391 // Error checking
392 if (cmdline.port != DEFAULT_PORT && gSessionData->mSessionXMLPath != NULL) {
393 logg->logError(__FILE__, __LINE__, "Only a port or a session xml can be specified, not both");
394 handleException();
395 }
396
397 if (gSessionData->mTargetPath != NULL && gSessionData->mSessionXMLPath == NULL) {
398 logg->logError(__FILE__, __LINE__, "Missing -s command line option required for a local capture.");
399 handleException();
400 }
401
402 if (optind < argc) {
403 logg->logError(__FILE__, __LINE__, "Unknown argument: %s. Use '-h' for help.", argv[optind]);
404 handleException();
405 }
406
407 return cmdline;
408}
409
410void handleClient() {
411 OlySocket client(sock->acceptConnection());
412
413 int pid = fork();
414 if (pid < 0) {
415 // Error
416 logg->logError(__FILE__, __LINE__, "Fork process failed. Please power cycle the target device if this error persists.");
417 } else if (pid == 0) {
418 // Child
419 sock->closeServerSocket();
420 udpListener.close();
421 monitor.close();
422 child = new Child(&client, numSessions + 1);
423 child->run();
424 delete child;
425 exit(0);
426 } else {
427 // Parent
428 client.closeSocket();
429
430 pthread_mutex_lock(&numSessions_mutex);
431 numSessions++;
432 pthread_mutex_unlock(&numSessions_mutex);
433
434 // Maximum number of connections is 2
435 int wait = 0;
436 while (numSessions > 1) {
437 // Throttle until one of the children exits before continuing to accept another socket connection
438 logg->logMessage("%d sessions active!", numSessions);
439 if (wait++ >= 10) { // Wait no more than 10 seconds
440 // Kill last created child
441 kill(pid, SIGALRM);
442 break;
443 }
444 sleep(1);
445 }
446 }
447}
448
449// Gator data flow: collector -> collector fifo -> sender
450int main(int argc, char** argv) {
451 // Ensure proper signal handling by making gatord the process group leader
452 // e.g. it may not be the group leader when launched as 'sudo gatord'
453 setsid();
454
455 logg = new Logging(DEBUG); // Set up global thread-safe logging
456 gSessionData = new SessionData(); // Global data class
457 util = new OlyUtility(); // Set up global utility class
458
459 // Initialize drivers
460 new KMod();
461
462 prctl(PR_SET_NAME, (unsigned long)&"gatord-main", 0, 0, 0);
463 pthread_mutex_init(&numSessions_mutex, NULL);
464
465 signal(SIGINT, handler);
466 signal(SIGTERM, handler);
467 signal(SIGABRT, handler);
468
469 // Set to high priority
470 if (setpriority(PRIO_PROCESS, syscall(__NR_gettid), -19) == -1) {
471 logg->logMessage("setpriority() failed");
472 }
473
474 // Parse the command line parameters
475 struct cmdline_t cmdline = parseCommandLine(argc, argv);
476
477 // Verify root permissions
478 uid_t euid = geteuid();
479 if (euid) {
480 logg->logError(__FILE__, __LINE__, "gatord must be launched with root privileges");
481 handleException();
482 }
483
484 // Call before setting up the SIGCHLD handler, as system() spawns child processes
485 if (!setupFilesystem(cmdline.module)) {
486 logg->logMessage("Unable to setup gatorfs, trying perf");
487 if (!gSessionData->perf.setup()) {
488 logg->logError(__FILE__, __LINE__,
489 "Unable to locate gator.ko driver:\n"
490 " >>> gator.ko should be co-located with gatord in the same directory\n"
491 " >>> OR insmod gator.ko prior to launching gatord\n"
492 " >>> OR specify the location of gator.ko on the command line\n"
493 " >>> OR run Linux 3.4 or later with perf (CONFIG_PERF_EVENTS and CONFIG_HW_PERF_EVENTS) and tracing (CONFIG_TRACING) support to collect data via userspace only");
494 handleException();
495 }
496 }
497
498 gSessionData->hwmon.setup();
499 {
500 EventsXML eventsXML;
501 mxml_node_t *xml = eventsXML.getTree();
502 gSessionData->fsDriver.setup(xml);
503 gSessionData->maliVideo.setup(xml);
504 mxmlDelete(xml);
505 }
506
507 // Handle child exit codes
508 signal(SIGCHLD, child_exit);
509
510 // Ignore the SIGPIPE signal so that any send to a broken socket will return an error code instead of asserting a signal
511 // Handling the error at the send function call is much easier than trying to do anything intelligent in the sig handler
512 signal(SIGPIPE, SIG_IGN);
513
514 // If the command line argument is a session xml file, no need to open a socket
515 if (gSessionData->mSessionXMLPath) {
516 child = new Child();
517 child->run();
518 delete child;
519 } else {
520 sock = new OlyServerSocket(cmdline.port);
521 udpListener.setup(cmdline.port);
522 if (!monitor.init() || !monitor.add(sock->getFd()) || !monitor.add(udpListener.getReq())) {
523 logg->logError(__FILE__, __LINE__, "Monitor setup failed");
524 handleException();
525 }
526 // Forever loop, can be exited via a signal or exception
527 while (1) {
528 struct epoll_event events[2];
529 logg->logMessage("Waiting on connection...");
530 int ready = monitor.wait(events, ARRAY_LENGTH(events), -1);
531 if (ready < 0) {
532 logg->logError(__FILE__, __LINE__, "Monitor::wait failed");
533 handleException();
534 }
535 for (int i = 0; i < ready; ++i) {
536 if (events[i].data.fd == sock->getFd()) {
537 handleClient();
538 } else if (events[i].data.fd == udpListener.getReq()) {
539 udpListener.handle();
540 }
541 }
542 }
543 }
544
545 cleanUp();
546 return 0;
547}
diff --git a/tools/gator/daemon/mxml/COPYING b/tools/gator/daemon/mxml/COPYING
new file mode 100644
index 00000000000..4d0aa78af22
--- /dev/null
+++ b/tools/gator/daemon/mxml/COPYING
@@ -0,0 +1,507 @@
1 Mini-XML License
2 September 18, 2010
3
4
5The Mini-XML library and included programs are provided under the
6terms of the GNU Library General Public License version 2 (LGPL2)
7with the following exceptions:
8
9 1. Static linking of applications to the Mini-XML library
10does not constitute a derivative work and does not require
11the author to provide source code for the application, use
12the shared Mini-XML libraries, or link their applications
13against a user-supplied version of Mini-XML.
14
15If you link the application to a modified version of
16Mini-XML, then the changes to Mini-XML must be provided
17under the terms of the LGPL2 in sections 1, 2, and 4.
18
19 2. You do not have to provide a copy of the Mini-XML license
20with programs that are linked to the Mini-XML library, nor
21do you have to identify the Mini-XML license in your
22program or documentation as required by section 6 of the
23LGPL2.
24
25
26 GNU LIBRARY GENERAL PUBLIC LICENSE
27 Version 2, June 1991
28
29 Copyright (C) 1991 Free Software Foundation, Inc.
30 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31
32 Everyone is permitted to copy and distribute verbatim copies
33 of this license document, but changing it is not allowed.
34
35 [This is the first released version of the library GPL. It is
36 numbered 2 because it goes with version 2 of the ordinary GPL.]
37
38 Preamble
39
40 The licenses for most software are designed to take away your
41freedom to share and change it. By contrast, the GNU General Public
42Licenses are intended to guarantee your freedom to share and change
43free software--to make sure the software is free for all its users.
44
45 This license, the Library General Public License, applies to some
46specially designated Free Software Foundation software, and to any
47other libraries whose authors decide to use it. You can use it for
48your libraries, too.
49
50 When we speak of free software, we are referring to freedom, not
51price. Our General Public Licenses are designed to make sure that you
52have the freedom to distribute copies of free software (and charge for
53this service if you wish), that you receive source code or can get it
54if you want it, that you can change the software or use pieces of it
55in new free programs; and that you know you can do these things.
56
57 To protect your rights, we need to make restrictions that forbid
58anyone to deny you these rights or to ask you to surrender the rights.
59These restrictions translate to certain responsibilities for you if
60you distribute copies of the library, or if you modify it.
61
62 For example, if you distribute copies of the library, whether gratis
63or for a fee, you must give the recipients all the rights that we gave
64you. You must make sure that they, too, receive or can get the source
65code. If you link a program with the library, you must provide
66complete object files to the recipients so that they can relink them
67with the library, after making changes to the library and recompiling
68it. And you must show them these terms so they know their rights.
69
70 Our method of protecting your rights has two steps: (1) copyright
71the library, and (2) offer you this license which gives you legal
72permission to copy, distribute and/or modify the library.
73
74 Also, for each distributor's protection, we want to make certain
75that everyone understands that there is no warranty for this free
76library. If the library is modified by someone else and passed on, we
77want its recipients to know that what they have is not the original
78version, so that any problems introduced by others will not reflect on
79the original authors' reputations.
80
81 Finally, any free program is threatened constantly by software
82patents. We wish to avoid the danger that companies distributing free
83software will individually obtain patent licenses, thus in effect
84transforming the program into proprietary software. To prevent this,
85we have made it clear that any patent must be licensed for everyone's
86free use or not licensed at all.
87
88 Most GNU software, including some libraries, is covered by the ordinary
89GNU General Public License, which was designed for utility programs. This
90license, the GNU Library General Public License, applies to certain
91designated libraries. This license is quite different from the ordinary
92one; be sure to read it in full, and don't assume that anything in it is
93the same as in the ordinary license.
94
95 The reason we have a separate public license for some libraries is that
96they blur the distinction we usually make between modifying or adding to a
97program and simply using it. Linking a program with a library, without
98changing the library, is in some sense simply using the library, and is
99analogous to running a utility program or application program. However, in
100a textual and legal sense, the linked executable is a combined work, a
101derivative of the original library, and the ordinary General Public License
102treats it as such.
103
104 Because of this blurred distinction, using the ordinary General
105Public License for libraries did not effectively promote software
106sharing, because most developers did not use the libraries. We
107concluded that weaker conditions might promote sharing better.
108
109 However, unrestricted linking of non-free programs would deprive the
110users of those programs of all benefit from the free status of the
111libraries themselves. This Library General Public License is intended to
112permit developers of non-free programs to use free libraries, while
113preserving your freedom as a user of such programs to change the free
114libraries that are incorporated in them. (We have not seen how to achieve
115this as regards changes in header files, but we have achieved it as regards
116changes in the actual functions of the Library.) The hope is that this
117will lead to faster development of free libraries.
118
119 The precise terms and conditions for copying, distribution and
120modification follow. Pay close attention to the difference between a
121"work based on the library" and a "work that uses the library". The
122former contains code derived from the library, while the latter only
123works together with the library.
124
125 Note that it is possible for a library to be covered by the ordinary
126General Public License rather than by this special one.
127
128 GNU LIBRARY GENERAL PUBLIC LICENSE
129 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
130
131 0. This License Agreement applies to any software library which
132contains a notice placed by the copyright holder or other authorized
133party saying it may be distributed under the terms of this Library
134General Public License (also called "this License"). Each licensee is
135addressed as "you".
136
137 A "library" means a collection of software functions and/or data
138prepared so as to be conveniently linked with application programs
139(which use some of those functions and data) to form executables.
140
141 The "Library", below, refers to any such software library or work
142which has been distributed under these terms. A "work based on the
143Library" means either the Library or any derivative work under
144copyright law: that is to say, a work containing the Library or a
145portion of it, either verbatim or with modifications and/or translated
146straightforwardly into another language. (Hereinafter, translation is
147included without limitation in the term "modification".)
148
149 "Source code" for a work means the preferred form of the work for
150making modifications to it. For a library, complete source code means
151all the source code for all modules it contains, plus any associated
152interface definition files, plus the scripts used to control compilation
153and installation of the library.
154
155 Activities other than copying, distribution and modification are not
156covered by this License; they are outside its scope. The act of
157running a program using the Library is not restricted, and output from
158such a program is covered only if its contents constitute a work based
159on the Library (independent of the use of the Library in a tool for
160writing it). Whether that is true depends on what the Library does
161and what the program that uses the Library does.
162
163 1. You may copy and distribute verbatim copies of the Library's
164complete source code as you receive it, in any medium, provided that
165you conspicuously and appropriately publish on each copy an
166appropriate copyright notice and disclaimer of warranty; keep intact
167all the notices that refer to this License and to the absence of any
168warranty; and distribute a copy of this License along with the
169Library.
170
171 You may charge a fee for the physical act of transferring a copy,
172and you may at your option offer warranty protection in exchange for a
173fee.
174
175 2. You may modify your copy or copies of the Library or any portion
176of it, thus forming a work based on the Library, and copy and
177distribute such modifications or work under the terms of Section 1
178above, provided that you also meet all of these conditions:
179
180 a) The modified work must itself be a software library.
181
182 b) You must cause the files modified to carry prominent notices
183 stating that you changed the files and the date of any change.
184
185 c) You must cause the whole of the work to be licensed at no
186 charge to all third parties under the terms of this License.
187
188 d) If a facility in the modified Library refers to a function or a
189 table of data to be supplied by an application program that uses
190 the facility, other than as an argument passed when the facility
191 is invoked, then you must make a good faith effort to ensure that,
192 in the event an application does not supply such function or
193 table, the facility still operates, and performs whatever part of
194 its purpose remains meaningful.
195
196 (For example, a function in a library to compute square roots has
197 a purpose that is entirely well-defined independent of the
198 application. Therefore, Subsection 2d requires that any
199 application-supplied function or table used by this function must
200 be optional: if the application does not supply it, the square
201 root function must still compute square roots.)
202
203These requirements apply to the modified work as a whole. If
204identifiable sections of that work are not derived from the Library,
205and can be reasonably considered independent and separate works in
206themselves, then this License, and its terms, do not apply to those
207sections when you distribute them as separate works. But when you
208distribute the same sections as part of a whole which is a work based
209on the Library, the distribution of the whole must be on the terms of
210this License, whose permissions for other licensees extend to the
211entire whole, and thus to each and every part regardless of who wrote
212it.
213
214Thus, it is not the intent of this section to claim rights or contest
215your rights to work written entirely by you; rather, the intent is to
216exercise the right to control the distribution of derivative or
217collective works based on the Library.
218
219In addition, mere aggregation of another work not based on the Library
220with the Library (or with a work based on the Library) on a volume of
221a storage or distribution medium does not bring the other work under
222the scope of this License.
223
224 3. You may opt to apply the terms of the ordinary GNU General Public
225License instead of this License to a given copy of the Library. To do
226this, you must alter all the notices that refer to this License, so
227that they refer to the ordinary GNU General Public License, version 2,
228instead of to this License. (If a newer version than version 2 of the
229ordinary GNU General Public License has appeared, then you can specify
230that version instead if you wish.) Do not make any other change in
231these notices.
232
233 Once this change is made in a given copy, it is irreversible for
234that copy, so the ordinary GNU General Public License applies to all
235subsequent copies and derivative works made from that copy.
236
237 This option is useful when you wish to copy part of the code of
238the Library into a program that is not a library.
239
240 4. You may copy and distribute the Library (or a portion or
241derivative of it, under Section 2) in object code or executable form
242under the terms of Sections 1 and 2 above provided that you accompany
243it with the complete corresponding machine-readable source code, which
244must be distributed under the terms of Sections 1 and 2 above on a
245medium customarily used for software interchange.
246
247 If distribution of object code is made by offering access to copy
248from a designated place, then offering equivalent access to copy the
249source code from the same place satisfies the requirement to
250distribute the source code, even though third parties are not
251compelled to copy the source along with the object code.
252
253 5. A program that contains no derivative of any portion of the
254Library, but is designed to work with the Library by being compiled or
255linked with it, is called a "work that uses the Library". Such a
256work, in isolation, is not a derivative work of the Library, and
257therefore falls outside the scope of this License.
258
259 However, linking a "work that uses the Library" with the Library
260creates an executable that is a derivative of the Library (because it
261contains portions of the Library), rather than a "work that uses the
262library". The executable is therefore covered by this License.
263Section 6 states terms for distribution of such executables.
264
265 When a "work that uses the Library" uses material from a header file
266that is part of the Library, the object code for the work may be a
267derivative work of the Library even though the source code is not.
268Whether this is true is especially significant if the work can be
269linked without the Library, or if the work is itself a library. The
270threshold for this to be true is not precisely defined by law.
271
272 If such an object file uses only numerical parameters, data
273structure layouts and accessors, and small macros and small inline
274functions (ten lines or less in length), then the use of the object
275file is unrestricted, regardless of whether it is legally a derivative
276work. (Executables containing this object code plus portions of the
277Library will still fall under Section 6.)
278
279 Otherwise, if the work is a derivative of the Library, you may
280distribute the object code for the work under the terms of Section 6.
281Any executables containing that work also fall under Section 6,
282whether or not they are linked directly with the Library itself.
283
284 6. As an exception to the Sections above, you may also compile or
285link a "work that uses the Library" with the Library to produce a
286work containing portions of the Library, and distribute that work
287under terms of your choice, provided that the terms permit
288modification of the work for the customer's own use and reverse
289engineering for debugging such modifications.
290
291 You must give prominent notice with each copy of the work that the
292Library is used in it and that the Library and its use are covered by
293this License. You must supply a copy of this License. If the work
294during execution displays copyright notices, you must include the
295copyright notice for the Library among them, as well as a reference
296directing the user to the copy of this License. Also, you must do one
297of these things:
298
299 a) Accompany the work with the complete corresponding
300 machine-readable source code for the Library including whatever
301 changes were used in the work (which must be distributed under
302 Sections 1 and 2 above); and, if the work is an executable linked
303 with the Library, with the complete machine-readable "work that
304 uses the Library", as object code and/or source code, so that the
305 user can modify the Library and then relink to produce a modified
306 executable containing the modified Library. (It is understood
307 that the user who changes the contents of definitions files in the
308 Library will not necessarily be able to recompile the application
309 to use the modified definitions.)
310
311 b) Accompany the work with a written offer, valid for at
312 least three years, to give the same user the materials
313 specified in Subsection 6a, above, for a charge no more
314 than the cost of performing this distribution.
315
316 c) If distribution of the work is made by offering access to copy
317 from a designated place, offer equivalent access to copy the above
318 specified materials from the same place.
319
320 d) Verify that the user has already received a copy of these
321 materials or that you have already sent this user a copy.
322
323 For an executable, the required form of the "work that uses the
324Library" must include any data and utility programs needed for
325reproducing the executable from it. However, as a special exception,
326the source code distributed need not include anything that is normally
327distributed (in either source or binary form) with the major
328components (compiler, kernel, and so on) of the operating system on
329which the executable runs, unless that component itself accompanies
330the executable.
331
332 It may happen that this requirement contradicts the license
333restrictions of other proprietary libraries that do not normally
334accompany the operating system. Such a contradiction means you cannot
335use both them and the Library together in an executable that you
336distribute.
337
338 7. You may place library facilities that are a work based on the
339Library side-by-side in a single library together with other library
340facilities not covered by this License, and distribute such a combined
341library, provided that the separate distribution of the work based on
342the Library and of the other library facilities is otherwise
343permitted, and provided that you do these two things:
344
345 a) Accompany the combined library with a copy of the same work
346 based on the Library, uncombined with any other library
347 facilities. This must be distributed under the terms of the
348 Sections above.
349
350 b) Give prominent notice with the combined library of the fact
351 that part of it is a work based on the Library, and explaining
352 where to find the accompanying uncombined form of the same work.
353
354 8. You may not copy, modify, sublicense, link with, or distribute
355the Library except as expressly provided under this License. Any
356attempt otherwise to copy, modify, sublicense, link with, or
357distribute the Library is void, and will automatically terminate your
358rights under this License. However, parties who have received copies,
359or rights, from you under this License will not have their licenses
360terminated so long as such parties remain in full compliance.
361
362 9. You are not required to accept this License, since you have not
363signed it. However, nothing else grants you permission to modify or
364distribute the Library or its derivative works. These actions are
365prohibited by law if you do not accept this License. Therefore, by
366modifying or distributing the Library (or any work based on the
367Library), you indicate your acceptance of this License to do so, and
368all its terms and conditions for copying, distributing or modifying
369the Library or works based on it.
370
371 10. Each time you redistribute the Library (or any work based on the
372Library), the recipient automatically receives a license from the
373original licensor to copy, distribute, link with or modify the Library
374subject to these terms and conditions. You may not impose any further
375restrictions on the recipients' exercise of the rights granted herein.
376You are not responsible for enforcing compliance by third parties to
377this License.
378
379 11. If, as a consequence of a court judgment or allegation of patent
380infringement or for any other reason (not limited to patent issues),
381conditions are imposed on you (whether by court order, agreement or
382otherwise) that contradict the conditions of this License, they do not
383excuse you from the conditions of this License. If you cannot
384distribute so as to satisfy simultaneously your obligations under this
385License and any other pertinent obligations, then as a consequence you
386may not distribute the Library at all. For example, if a patent
387license would not permit royalty-free redistribution of the Library by
388all those who receive copies directly or indirectly through you, then
389the only way you could satisfy both it and this License would be to
390refrain entirely from distribution of the Library.
391
392If any portion of this section is held invalid or unenforceable under any
393particular circumstance, the balance of the section is intended to apply,
394and the section as a whole is intended to apply in other circumstances.
395
396It is not the purpose of this section to induce you to infringe any
397patents or other property right claims or to contest validity of any
398such claims; this section has the sole purpose of protecting the
399integrity of the free software distribution system which is
400implemented by public license practices. Many people have made
401generous contributions to the wide range of software distributed
402through that system in reliance on consistent application of that
403system; it is up to the author/donor to decide if he or she is willing
404to distribute software through any other system and a licensee cannot
405impose that choice.
406
407This section is intended to make thoroughly clear what is believed to
408be a consequence of the rest of this License.
409
410 12. If the distribution and/or use of the Library is restricted in
411certain countries either by patents or by copyrighted interfaces, the
412original copyright holder who places the Library under this License may add
413an explicit geographical distribution limitation excluding those countries,
414so that distribution is permitted only in or among countries not thus
415excluded. In such case, this License incorporates the limitation as if
416written in the body of this License.
417
418 13. The Free Software Foundation may publish revised and/or new
419versions of the Library General Public License from time to time.
420Such new versions will be similar in spirit to the present version,
421but may differ in detail to address new problems or concerns.
422
423Each version is given a distinguishing version number. If the Library
424specifies a version number of this License which applies to it and
425"any later version", you have the option of following the terms and
426conditions either of that version or of any later version published by
427the Free Software Foundation. If the Library does not specify a
428license version number, you may choose any version ever published by
429the Free Software Foundation.
430
431 14. If you wish to incorporate parts of the Library into other free
432programs whose distribution conditions are incompatible with these,
433write to the author to ask for permission. For software which is
434copyrighted by the Free Software Foundation, write to the Free
435Software Foundation; we sometimes make exceptions for this. Our
436decision will be guided by the two goals of preserving the free status
437of all derivatives of our free software and of promoting the sharing
438and reuse of software generally.
439
440 NO WARRANTY
441
442 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
443WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
444EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
445OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
446KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
447IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
448PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
449LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
450THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
451
452 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
453WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
454AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
455FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
456CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
457LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
458RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
459FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
460SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
461DAMAGES.
462
463 END OF TERMS AND CONDITIONS
464
465 Appendix: How to Apply These Terms to Your New Libraries
466
467 If you develop a new library, and you want it to be of the greatest
468possible use to the public, we recommend making it free software that
469everyone can redistribute and change. You can do so by permitting
470redistribution under these terms (or, alternatively, under the terms of the
471ordinary General Public License).
472
473 To apply these terms, attach the following notices to the library. It is
474safest to attach them to the start of each source file to most effectively
475convey the exclusion of warranty; and each file should have at least the
476"copyright" line and a pointer to where the full notice is found.
477
478 <one line to give the library's name and a brief idea of what it does.>
479 Copyright (C) <year> <name of author>
480
481 This library is free software; you can redistribute it and/or
482 modify it under the terms of the GNU Library General Public
483 License as published by the Free Software Foundation; either
484 version 2 of the License, or (at your option) any later version.
485
486 This library is distributed in the hope that it will be useful,
487 but WITHOUT ANY WARRANTY; without even the implied warranty of
488 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
489 Library General Public License for more details.
490
491 You should have received a copy of the GNU Library General Public
492 License along with this library; if not, write to the Free
493 Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
494
495Also add information on how to contact you by electronic and paper mail.
496
497You should also get your employer (if you work as a programmer) or your
498school, if any, to sign a "copyright disclaimer" for the library, if
499necessary. Here is a sample; alter the names:
500
501 Yoyodyne, Inc., hereby disclaims all copyright interest in the
502 library `Frob' (a library for tweaking knobs) written by James Random Hacker.
503
504 <signature of Ty Coon>, 1 April 1990
505 Ty Coon, President of Vice
506
507That's all there is to it!
diff --git a/tools/gator/daemon/mxml/config.h b/tools/gator/daemon/mxml/config.h
new file mode 100644
index 00000000000..1f59ba34a47
--- /dev/null
+++ b/tools/gator/daemon/mxml/config.h
@@ -0,0 +1,96 @@
1/* config.h. Generated from config.h.in by configure. */
2/*
3 * "$Id: config.h.in 408 2010-09-19 05:26:46Z mike $"
4 *
5 * Configuration file for Mini-XML, a small XML-like file parsing library.
6 *
7 * Copyright 2003-2010 by Michael R Sweet.
8 *
9 * These coded instructions, statements, and computer programs are the
10 * property of Michael R Sweet and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "COPYING"
12 * which should have been included with this file. If this file is
13 * missing or damaged, see the license at:
14 *
15 * http://www.minixml.org/
16 */
17
18/*
19 * Include necessary headers...
20 */
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <stdarg.h>
26#include <ctype.h>
27
28
29/*
30 * Version number...
31 */
32
33#define MXML_VERSION "Mini-XML v2.7"
34
35
36/*
37 * Inline function support...
38 */
39
40#define inline
41
42
43/*
44 * Long long support...
45 */
46
47#define HAVE_LONG_LONG 1
48
49
50/*
51 * Do we have the snprintf() and vsnprintf() functions?
52 */
53
54#define HAVE_SNPRINTF 1
55#define HAVE_VSNPRINTF 1
56
57
58/*
59 * Do we have the strXXX() functions?
60 */
61
62#define HAVE_STRDUP 1
63
64
65/*
66 * Do we have threading support?
67 */
68
69#define HAVE_PTHREAD_H 1
70
71
72/*
73 * Define prototypes for string functions as needed...
74 */
75
76# ifndef HAVE_STRDUP
77extern char *_mxml_strdup(const char *);
78# define strdup _mxml_strdup
79# endif /* !HAVE_STRDUP */
80
81extern char *_mxml_strdupf(const char *, ...);
82extern char *_mxml_vstrdupf(const char *, va_list);
83
84# ifndef HAVE_SNPRINTF
85extern int _mxml_snprintf(char *, size_t, const char *, ...);
86# define snprintf _mxml_snprintf
87# endif /* !HAVE_SNPRINTF */
88
89# ifndef HAVE_VSNPRINTF
90extern int _mxml_vsnprintf(char *, size_t, const char *, va_list);
91# define vsnprintf _mxml_vsnprintf
92# endif /* !HAVE_VSNPRINTF */
93
94/*
95 * End of "$Id: config.h.in 408 2010-09-19 05:26:46Z mike $".
96 */
diff --git a/tools/gator/daemon/mxml/mxml-attr.c b/tools/gator/daemon/mxml/mxml-attr.c
new file mode 100644
index 00000000000..c9950f5fb73
--- /dev/null
+++ b/tools/gator/daemon/mxml/mxml-attr.c
@@ -0,0 +1,319 @@
1/*
2 * "$Id: mxml-attr.c 408 2010-09-19 05:26:46Z mike $"
3 *
4 * Attribute support code for Mini-XML, a small XML-like file parsing library.
5 *
6 * Copyright 2003-2010 by Michael R Sweet.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Michael R Sweet and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "COPYING"
11 * which should have been included with this file. If this file is
12 * missing or damaged, see the license at:
13 *
14 * http://www.minixml.org/
15 *
16 * Contents:
17 *
18 * mxmlElementDeleteAttr() - Delete an attribute.
19 * mxmlElementGetAttr() - Get an attribute.
20 * mxmlElementSetAttr() - Set an attribute.
21 * mxmlElementSetAttrf() - Set an attribute with a formatted value.
22 * mxml_set_attr() - Set or add an attribute name/value pair.
23 */
24
25/*
26 * Include necessary headers...
27 */
28
29#include "config.h"
30#include "mxml.h"
31
32
33/*
34 * Local functions...
35 */
36
37static int mxml_set_attr(mxml_node_t *node, const char *name,
38 char *value);
39
40
41/*
42 * 'mxmlElementDeleteAttr()' - Delete an attribute.
43 *
44 * @since Mini-XML 2.4@
45 */
46
47void
48mxmlElementDeleteAttr(mxml_node_t *node,/* I - Element */
49 const char *name)/* I - Attribute name */
50{
51 int i; /* Looping var */
52 mxml_attr_t *attr; /* Cirrent attribute */
53
54
55#ifdef DEBUG
56 fprintf(stderr, "mxmlElementDeleteAttr(node=%p, name=\"%s\")\n",
57 node, name ? name : "(null)");
58#endif /* DEBUG */
59
60 /*
61 * Range check input...
62 */
63
64 if (!node || node->type != MXML_ELEMENT || !name)
65 return;
66
67 /*
68 * Look for the attribute...
69 */
70
71 for (i = node->value.element.num_attrs, attr = node->value.element.attrs;
72 i > 0;
73 i --, attr ++)
74 {
75#ifdef DEBUG
76 printf(" %s=\"%s\"\n", attr->name, attr->value);
77#endif /* DEBUG */
78
79 if (!strcmp(attr->name, name))
80 {
81 /*
82 * Delete this attribute...
83 */
84
85 free(attr->name);
86 free(attr->value);
87
88 i --;
89 if (i > 0)
90 memmove(attr, attr + 1, i * sizeof(mxml_attr_t));
91
92 node->value.element.num_attrs --;
93 return;
94 }
95 }
96}
97
98
99/*
100 * 'mxmlElementGetAttr()' - Get an attribute.
101 *
102 * This function returns NULL if the node is not an element or the
103 * named attribute does not exist.
104 */
105
106const char * /* O - Attribute value or NULL */
107mxmlElementGetAttr(mxml_node_t *node, /* I - Element node */
108 const char *name) /* I - Name of attribute */
109{
110 int i; /* Looping var */
111 mxml_attr_t *attr; /* Cirrent attribute */
112
113
114#ifdef DEBUG
115 fprintf(stderr, "mxmlElementGetAttr(node=%p, name=\"%s\")\n",
116 node, name ? name : "(null)");
117#endif /* DEBUG */
118
119 /*
120 * Range check input...
121 */
122
123 if (!node || node->type != MXML_ELEMENT || !name)
124 return (NULL);
125
126 /*
127 * Look for the attribute...
128 */
129
130 for (i = node->value.element.num_attrs, attr = node->value.element.attrs;
131 i > 0;
132 i --, attr ++)
133 {
134#ifdef DEBUG
135 printf(" %s=\"%s\"\n", attr->name, attr->value);
136#endif /* DEBUG */
137
138 if (!strcmp(attr->name, name))
139 {
140#ifdef DEBUG
141 printf(" Returning \"%s\"!\n", attr->value);
142#endif /* DEBUG */
143 return (attr->value);
144 }
145 }
146
147 /*
148 * Didn't find attribute, so return NULL...
149 */
150
151#ifdef DEBUG
152 puts(" Returning NULL!\n");
153#endif /* DEBUG */
154
155 return (NULL);
156}
157
158
159/*
160 * 'mxmlElementSetAttr()' - Set an attribute.
161 *
162 * If the named attribute already exists, the value of the attribute
163 * is replaced by the new string value. The string value is copied
164 * into the element node. This function does nothing if the node is
165 * not an element.
166 */
167
168void
169mxmlElementSetAttr(mxml_node_t *node, /* I - Element node */
170 const char *name, /* I - Name of attribute */
171 const char *value) /* I - Attribute value */
172{
173 char *valuec; /* Copy of value */
174
175
176#ifdef DEBUG
177 fprintf(stderr, "mxmlElementSetAttr(node=%p, name=\"%s\", value=\"%s\")\n",
178 node, name ? name : "(null)", value ? value : "(null)");
179#endif /* DEBUG */
180
181 /*
182 * Range check input...
183 */
184
185 if (!node || node->type != MXML_ELEMENT || !name)
186 return;
187
188 if (value)
189 valuec = strdup(value);
190 else
191 valuec = NULL;
192
193 if (mxml_set_attr(node, name, valuec))
194 free(valuec);
195}
196
197
198/*
199 * 'mxmlElementSetAttrf()' - Set an attribute with a formatted value.
200 *
201 * If the named attribute already exists, the value of the attribute
202 * is replaced by the new formatted string. The formatted string value is
203 * copied into the element node. This function does nothing if the node
204 * is not an element.
205 *
206 * @since Mini-XML 2.3@
207 */
208
209void
210mxmlElementSetAttrf(mxml_node_t *node, /* I - Element node */
211 const char *name, /* I - Name of attribute */
212 const char *format,/* I - Printf-style attribute value */
213 ...) /* I - Additional arguments as needed */
214{
215 va_list ap; /* Argument pointer */
216 char *value; /* Value */
217
218
219#ifdef DEBUG
220 fprintf(stderr,
221 "mxmlElementSetAttrf(node=%p, name=\"%s\", format=\"%s\", ...)\n",
222 node, name ? name : "(null)", format ? format : "(null)");
223#endif /* DEBUG */
224
225 /*
226 * Range check input...
227 */
228
229 if (!node || node->type != MXML_ELEMENT || !name || !format)
230 return;
231
232 /*
233 * Format the value...
234 */
235
236 va_start(ap, format);
237 value = _mxml_vstrdupf(format, ap);
238 va_end(ap);
239
240 if (!value)
241 mxml_error("Unable to allocate memory for attribute '%s' in element %s!",
242 name, node->value.element.name);
243 else if (mxml_set_attr(node, name, value))
244 free(value);
245}
246
247
248/*
249 * 'mxml_set_attr()' - Set or add an attribute name/value pair.
250 */
251
252static int /* O - 0 on success, -1 on failure */
253mxml_set_attr(mxml_node_t *node, /* I - Element node */
254 const char *name, /* I - Attribute name */
255 char *value) /* I - Attribute value */
256{
257 int i; /* Looping var */
258 mxml_attr_t *attr; /* New attribute */
259
260
261 /*
262 * Look for the attribute...
263 */
264
265 for (i = node->value.element.num_attrs, attr = node->value.element.attrs;
266 i > 0;
267 i --, attr ++)
268 if (!strcmp(attr->name, name))
269 {
270 /*
271 * Free the old value as needed...
272 */
273
274 if (attr->value)
275 free(attr->value);
276
277 attr->value = value;
278
279 return (0);
280 }
281
282 /*
283 * Add a new attribute...
284 */
285
286 if (node->value.element.num_attrs == 0)
287 attr = malloc(sizeof(mxml_attr_t));
288 else
289 attr = realloc(node->value.element.attrs,
290 (node->value.element.num_attrs + 1) * sizeof(mxml_attr_t));
291
292 if (!attr)
293 {
294 mxml_error("Unable to allocate memory for attribute '%s' in element %s!",
295 name, node->value.element.name);
296 return (-1);
297 }
298
299 node->value.element.attrs = attr;
300 attr += node->value.element.num_attrs;
301
302 if ((attr->name = strdup(name)) == NULL)
303 {
304 mxml_error("Unable to allocate memory for attribute '%s' in element %s!",
305 name, node->value.element.name);
306 return (-1);
307 }
308
309 attr->value = value;
310
311 node->value.element.num_attrs ++;
312
313 return (0);
314}
315
316
317/*
318 * End of "$Id: mxml-attr.c 408 2010-09-19 05:26:46Z mike $".
319 */
diff --git a/tools/gator/daemon/mxml/mxml-entity.c b/tools/gator/daemon/mxml/mxml-entity.c
new file mode 100644
index 00000000000..c5c9f61f73c
--- /dev/null
+++ b/tools/gator/daemon/mxml/mxml-entity.c
@@ -0,0 +1,460 @@
1/*
2 * "$Id: mxml-entity.c 408 2010-09-19 05:26:46Z mike $"
3 *
4 * Character entity support code for Mini-XML, a small XML-like
5 * file parsing library.
6 *
7 * Copyright 2003-2010 by Michael R Sweet.
8 *
9 * These coded instructions, statements, and computer programs are the
10 * property of Michael R Sweet and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "COPYING"
12 * which should have been included with this file. If this file is
13 * missing or damaged, see the license at:
14 *
15 * http://www.minixml.org/
16 *
17 * Contents:
18 *
19 * mxmlEntityAddCallback() - Add a callback to convert entities to
20 * Unicode.
21 * mxmlEntityGetName() - Get the name that corresponds to the
22 * character value.
23 * mxmlEntityGetValue() - Get the character corresponding to a named
24 * entity.
25 * mxmlEntityRemoveCallback() - Remove a callback.
26 * _mxml_entity_cb() - Lookup standard (X)HTML entities.
27 */
28
29/*
30 * Include necessary headers...
31 */
32
33#include "mxml-private.h"
34
35
36/*
37 * 'mxmlEntityAddCallback()' - Add a callback to convert entities to Unicode.
38 */
39
40int /* O - 0 on success, -1 on failure */
41mxmlEntityAddCallback(
42 mxml_entity_cb_t cb) /* I - Callback function to add */
43{
44 _mxml_global_t *global = _mxml_global();
45 /* Global data */
46
47
48 if (global->num_entity_cbs < (int)(sizeof(global->entity_cbs) / sizeof(global->entity_cbs[0])))
49 {
50 global->entity_cbs[global->num_entity_cbs] = cb;
51 global->num_entity_cbs ++;
52
53 return (0);
54 }
55 else
56 {
57 mxml_error("Unable to add entity callback!");
58
59 return (-1);
60 }
61}
62
63
64/*
65 * 'mxmlEntityGetName()' - Get the name that corresponds to the character value.
66 *
67 * If val does not need to be represented by a named entity, NULL is returned.
68 */
69
70const char * /* O - Entity name or NULL */
71mxmlEntityGetName(int val) /* I - Character value */
72{
73 switch (val)
74 {
75 case '&' :
76 return ("amp");
77
78 case '<' :
79 return ("lt");
80
81 case '>' :
82 return ("gt");
83
84 case '\"' :
85 return ("quot");
86
87 default :
88 return (NULL);
89 }
90}
91
92
93/*
94 * 'mxmlEntityGetValue()' - Get the character corresponding to a named entity.
95 *
96 * The entity name can also be a numeric constant. -1 is returned if the
97 * name is not known.
98 */
99
100int /* O - Character value or -1 on error */
101mxmlEntityGetValue(const char *name) /* I - Entity name */
102{
103 int i; /* Looping var */
104 int ch; /* Character value */
105 _mxml_global_t *global = _mxml_global();
106 /* Global data */
107
108
109 for (i = 0; i < global->num_entity_cbs; i ++)
110 if ((ch = (global->entity_cbs[i])(name)) >= 0)
111 return (ch);
112
113 return (-1);
114}
115
116
117/*
118 * 'mxmlEntityRemoveCallback()' - Remove a callback.
119 */
120
121void
122mxmlEntityRemoveCallback(
123 mxml_entity_cb_t cb) /* I - Callback function to remove */
124{
125 int i; /* Looping var */
126 _mxml_global_t *global = _mxml_global();
127 /* Global data */
128
129
130 for (i = 0; i < global->num_entity_cbs; i ++)
131 if (cb == global->entity_cbs[i])
132 {
133 /*
134 * Remove the callback...
135 */
136
137 global->num_entity_cbs --;
138
139 if (i < global->num_entity_cbs)
140 memmove(global->entity_cbs + i, global->entity_cbs + i + 1,
141 (global->num_entity_cbs - i) * sizeof(global->entity_cbs[0]));
142
143 return;
144 }
145}
146
147
148/*
149 * '_mxml_entity_cb()' - Lookup standard (X)HTML entities.
150 */
151
152int /* O - Unicode value or -1 */
153_mxml_entity_cb(const char *name) /* I - Entity name */
154{
155 int diff, /* Difference between names */
156 current, /* Current entity in search */
157 first, /* First entity in search */
158 last; /* Last entity in search */
159 static const struct
160 {
161 const char *name; /* Entity name */
162 int val; /* Character value */
163 } entities[] =
164 {
165 { "AElig", 198 },
166 { "Aacute", 193 },
167 { "Acirc", 194 },
168 { "Agrave", 192 },
169 { "Alpha", 913 },
170 { "Aring", 197 },
171 { "Atilde", 195 },
172 { "Auml", 196 },
173 { "Beta", 914 },
174 { "Ccedil", 199 },
175 { "Chi", 935 },
176 { "Dagger", 8225 },
177 { "Delta", 916 },
178 { "Dstrok", 208 },
179 { "ETH", 208 },
180 { "Eacute", 201 },
181 { "Ecirc", 202 },
182 { "Egrave", 200 },
183 { "Epsilon", 917 },
184 { "Eta", 919 },
185 { "Euml", 203 },
186 { "Gamma", 915 },
187 { "Iacute", 205 },
188 { "Icirc", 206 },
189 { "Igrave", 204 },
190 { "Iota", 921 },
191 { "Iuml", 207 },
192 { "Kappa", 922 },
193 { "Lambda", 923 },
194 { "Mu", 924 },
195 { "Ntilde", 209 },
196 { "Nu", 925 },
197 { "OElig", 338 },
198 { "Oacute", 211 },
199 { "Ocirc", 212 },
200 { "Ograve", 210 },
201 { "Omega", 937 },
202 { "Omicron", 927 },
203 { "Oslash", 216 },
204 { "Otilde", 213 },
205 { "Ouml", 214 },
206 { "Phi", 934 },
207 { "Pi", 928 },
208 { "Prime", 8243 },
209 { "Psi", 936 },
210 { "Rho", 929 },
211 { "Scaron", 352 },
212 { "Sigma", 931 },
213 { "THORN", 222 },
214 { "Tau", 932 },
215 { "Theta", 920 },
216 { "Uacute", 218 },
217 { "Ucirc", 219 },
218 { "Ugrave", 217 },
219 { "Upsilon", 933 },
220 { "Uuml", 220 },
221 { "Xi", 926 },
222 { "Yacute", 221 },
223 { "Yuml", 376 },
224 { "Zeta", 918 },
225 { "aacute", 225 },
226 { "acirc", 226 },
227 { "acute", 180 },
228 { "aelig", 230 },
229 { "agrave", 224 },
230 { "alefsym", 8501 },
231 { "alpha", 945 },
232 { "amp", '&' },
233 { "and", 8743 },
234 { "ang", 8736 },
235 { "apos", '\'' },
236 { "aring", 229 },
237 { "asymp", 8776 },
238 { "atilde", 227 },
239 { "auml", 228 },
240 { "bdquo", 8222 },
241 { "beta", 946 },
242 { "brkbar", 166 },
243 { "brvbar", 166 },
244 { "bull", 8226 },
245 { "cap", 8745 },
246 { "ccedil", 231 },
247 { "cedil", 184 },
248 { "cent", 162 },
249 { "chi", 967 },
250 { "circ", 710 },
251 { "clubs", 9827 },
252 { "cong", 8773 },
253 { "copy", 169 },
254 { "crarr", 8629 },
255 { "cup", 8746 },
256 { "curren", 164 },
257 { "dArr", 8659 },
258 { "dagger", 8224 },
259 { "darr", 8595 },
260 { "deg", 176 },
261 { "delta", 948 },
262 { "diams", 9830 },
263 { "die", 168 },
264 { "divide", 247 },
265 { "eacute", 233 },
266 { "ecirc", 234 },
267 { "egrave", 232 },
268 { "empty", 8709 },
269 { "emsp", 8195 },
270 { "ensp", 8194 },
271 { "epsilon", 949 },
272 { "equiv", 8801 },
273 { "eta", 951 },
274 { "eth", 240 },
275 { "euml", 235 },
276 { "euro", 8364 },
277 { "exist", 8707 },
278 { "fnof", 402 },
279 { "forall", 8704 },
280 { "frac12", 189 },
281 { "frac14", 188 },
282 { "frac34", 190 },
283 { "frasl", 8260 },
284 { "gamma", 947 },
285 { "ge", 8805 },
286 { "gt", '>' },
287 { "hArr", 8660 },
288 { "harr", 8596 },
289 { "hearts", 9829 },
290 { "hellip", 8230 },
291 { "hibar", 175 },
292 { "iacute", 237 },
293 { "icirc", 238 },
294 { "iexcl", 161 },
295 { "igrave", 236 },
296 { "image", 8465 },
297 { "infin", 8734 },
298 { "int", 8747 },
299 { "iota", 953 },
300 { "iquest", 191 },
301 { "isin", 8712 },
302 { "iuml", 239 },
303 { "kappa", 954 },
304 { "lArr", 8656 },
305 { "lambda", 955 },
306 { "lang", 9001 },
307 { "laquo", 171 },
308 { "larr", 8592 },
309 { "lceil", 8968 },
310 { "ldquo", 8220 },
311 { "le", 8804 },
312 { "lfloor", 8970 },
313 { "lowast", 8727 },
314 { "loz", 9674 },
315 { "lrm", 8206 },
316 { "lsaquo", 8249 },
317 { "lsquo", 8216 },
318 { "lt", '<' },
319 { "macr", 175 },
320 { "mdash", 8212 },
321 { "micro", 181 },
322 { "middot", 183 },
323 { "minus", 8722 },
324 { "mu", 956 },
325 { "nabla", 8711 },
326 { "nbsp", 160 },
327 { "ndash", 8211 },
328 { "ne", 8800 },
329 { "ni", 8715 },
330 { "not", 172 },
331 { "notin", 8713 },
332 { "nsub", 8836 },
333 { "ntilde", 241 },
334 { "nu", 957 },
335 { "oacute", 243 },
336 { "ocirc", 244 },
337 { "oelig", 339 },
338 { "ograve", 242 },
339 { "oline", 8254 },
340 { "omega", 969 },
341 { "omicron", 959 },
342 { "oplus", 8853 },
343 { "or", 8744 },
344 { "ordf", 170 },
345 { "ordm", 186 },
346 { "oslash", 248 },
347 { "otilde", 245 },
348 { "otimes", 8855 },
349 { "ouml", 246 },
350 { "para", 182 },
351 { "part", 8706 },
352 { "permil", 8240 },
353 { "perp", 8869 },
354 { "phi", 966 },
355 { "pi", 960 },
356 { "piv", 982 },
357 { "plusmn", 177 },
358 { "pound", 163 },
359 { "prime", 8242 },
360 { "prod", 8719 },
361 { "prop", 8733 },
362 { "psi", 968 },
363 { "quot", '\"' },
364 { "rArr", 8658 },
365 { "radic", 8730 },
366 { "rang", 9002 },
367 { "raquo", 187 },
368 { "rarr", 8594 },
369 { "rceil", 8969 },
370 { "rdquo", 8221 },
371 { "real", 8476 },
372 { "reg", 174 },
373 { "rfloor", 8971 },
374 { "rho", 961 },
375 { "rlm", 8207 },
376 { "rsaquo", 8250 },
377 { "rsquo", 8217 },
378 { "sbquo", 8218 },
379 { "scaron", 353 },
380 { "sdot", 8901 },
381 { "sect", 167 },
382 { "shy", 173 },
383 { "sigma", 963 },
384 { "sigmaf", 962 },
385 { "sim", 8764 },
386 { "spades", 9824 },
387 { "sub", 8834 },
388 { "sube", 8838 },
389 { "sum", 8721 },
390 { "sup", 8835 },
391 { "sup1", 185 },
392 { "sup2", 178 },
393 { "sup3", 179 },
394 { "supe", 8839 },
395 { "szlig", 223 },
396 { "tau", 964 },
397 { "there4", 8756 },
398 { "theta", 952 },
399 { "thetasym", 977 },
400 { "thinsp", 8201 },
401 { "thorn", 254 },
402 { "tilde", 732 },
403 { "times", 215 },
404 { "trade", 8482 },
405 { "uArr", 8657 },
406 { "uacute", 250 },
407 { "uarr", 8593 },
408 { "ucirc", 251 },
409 { "ugrave", 249 },
410 { "uml", 168 },
411 { "upsih", 978 },
412 { "upsilon", 965 },
413 { "uuml", 252 },
414 { "weierp", 8472 },
415 { "xi", 958 },
416 { "yacute", 253 },
417 { "yen", 165 },
418 { "yuml", 255 },
419 { "zeta", 950 },
420 { "zwj", 8205 },
421 { "zwnj", 8204 }
422 };
423
424
425 /*
426 * Do a binary search for the named entity...
427 */
428
429 first = 0;
430 last = (int)(sizeof(entities) / sizeof(entities[0]) - 1);
431
432 while ((last - first) > 1)
433 {
434 current = (first + last) / 2;
435
436 if ((diff = strcmp(name, entities[current].name)) == 0)
437 return (entities[current].val);
438 else if (diff < 0)
439 last = current;
440 else
441 first = current;
442 }
443
444 /*
445 * If we get here, there is a small chance that there is still
446 * a match; check first and last...
447 */
448
449 if (!strcmp(name, entities[first].name))
450 return (entities[first].val);
451 else if (!strcmp(name, entities[last].name))
452 return (entities[last].val);
453 else
454 return (-1);
455}
456
457
458/*
459 * End of "$Id: mxml-entity.c 408 2010-09-19 05:26:46Z mike $".
460 */
diff --git a/tools/gator/daemon/mxml/mxml-file.c b/tools/gator/daemon/mxml/mxml-file.c
new file mode 100644
index 00000000000..7860ee5f837
--- /dev/null
+++ b/tools/gator/daemon/mxml/mxml-file.c
@@ -0,0 +1,3082 @@
1/*
2 * "$Id: mxml-file.c 438 2011-03-24 05:47:51Z mike $"
3 *
4 * File loading code for Mini-XML, a small XML-like file parsing library.
5 *
6 * Copyright 2003-2011 by Michael R Sweet.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Michael R Sweet and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "COPYING"
11 * which should have been included with this file. If this file is
12 * missing or damaged, see the license at:
13 *
14 * http://www.minixml.org/
15 *
16 * Contents:
17 *
18 * mxmlLoadFd() - Load a file descriptor into an XML node tree.
19 * mxmlLoadFile() - Load a file into an XML node tree.
20 * mxmlLoadString() - Load a string into an XML node tree.
21 * mxmlSaveAllocString() - Save an XML tree to an allocated string.
22 * mxmlSaveFd() - Save an XML tree to a file descriptor.
23 * mxmlSaveFile() - Save an XML tree to a file.
24 * mxmlSaveString() - Save an XML node tree to a string.
25 * mxmlSAXLoadFd() - Load a file descriptor into an XML node tree
26 * using a SAX callback.
27 * mxmlSAXLoadFile() - Load a file into an XML node tree
28 * using a SAX callback.
29 * mxmlSAXLoadString() - Load a string into an XML node tree
30 * using a SAX callback.
31 * mxmlSetCustomHandlers() - Set the handling functions for custom data.
32 * mxmlSetErrorCallback() - Set the error message callback.
33 * mxmlSetWrapMargin() - Set the wrap margin when saving XML data.
34 * mxml_add_char() - Add a character to a buffer, expanding as needed.
35 * mxml_fd_getc() - Read a character from a file descriptor.
36 * mxml_fd_putc() - Write a character to a file descriptor.
37 * mxml_fd_read() - Read a buffer of data from a file descriptor.
38 * mxml_fd_write() - Write a buffer of data to a file descriptor.
39 * mxml_file_getc() - Get a character from a file.
40 * mxml_file_putc() - Write a character to a file.
41 * mxml_get_entity() - Get the character corresponding to an entity...
42 * mxml_load_data() - Load data into an XML node tree.
43 * mxml_parse_element() - Parse an element for any attributes...
44 * mxml_string_getc() - Get a character from a string.
45 * mxml_string_putc() - Write a character to a string.
46 * mxml_write_name() - Write a name string.
47 * mxml_write_node() - Save an XML node to a file.
48 * mxml_write_string() - Write a string, escaping & and < as needed.
49 * mxml_write_ws() - Do whitespace callback...
50 */
51
52/*
53 * Include necessary headers...
54 */
55
56#ifndef WIN32
57# include <unistd.h>
58#endif /* !WIN32 */
59#include "mxml-private.h"
60
61
62/*
63 * Character encoding...
64 */
65
66#define ENCODE_UTF8 0 /* UTF-8 */
67#define ENCODE_UTF16BE 1 /* UTF-16 Big-Endian */
68#define ENCODE_UTF16LE 2 /* UTF-16 Little-Endian */
69
70
71/*
72 * Macro to test for a bad XML character...
73 */
74
75#define mxml_bad_char(ch) ((ch) < ' ' && (ch) != '\n' && (ch) != '\r' && (ch) != '\t')
76
77
78/*
79 * Types and structures...
80 */
81
82typedef int (*_mxml_getc_cb_t)(void *, int *);
83typedef int (*_mxml_putc_cb_t)(int, void *);
84
85typedef struct _mxml_fdbuf_s /**** File descriptor buffer ****/
86{
87 int fd; /* File descriptor */
88 unsigned char *current, /* Current position in buffer */
89 *end, /* End of buffer */
90 buffer[8192]; /* Character buffer */
91} _mxml_fdbuf_t;
92
93
94/*
95 * Local functions...
96 */
97
98static int mxml_add_char(int ch, char **ptr, char **buffer,
99 int *bufsize);
100static int mxml_fd_getc(void *p, int *encoding);
101static int mxml_fd_putc(int ch, void *p);
102static int mxml_fd_read(_mxml_fdbuf_t *buf);
103static int mxml_fd_write(_mxml_fdbuf_t *buf);
104static int mxml_file_getc(void *p, int *encoding);
105static int mxml_file_putc(int ch, void *p);
106static int mxml_get_entity(mxml_node_t *parent, void *p,
107 int *encoding,
108 _mxml_getc_cb_t getc_cb);
109static inline int mxml_isspace(int ch)
110 {
111 return (ch == ' ' || ch == '\t' || ch == '\r' ||
112 ch == '\n');
113 }
114static mxml_node_t *mxml_load_data(mxml_node_t *top, void *p,
115 mxml_load_cb_t cb,
116 _mxml_getc_cb_t getc_cb,
117 mxml_sax_cb_t sax_cb, void *sax_data);
118static int mxml_parse_element(mxml_node_t *node, void *p,
119 int *encoding,
120 _mxml_getc_cb_t getc_cb);
121static int mxml_string_getc(void *p, int *encoding);
122static int mxml_string_putc(int ch, void *p);
123static int mxml_write_name(const char *s, void *p,
124 _mxml_putc_cb_t putc_cb);
125static int mxml_write_node(mxml_node_t *node, void *p,
126 mxml_save_cb_t cb, int col,
127 _mxml_putc_cb_t putc_cb,
128 _mxml_global_t *global);
129static int mxml_write_string(const char *s, void *p,
130 _mxml_putc_cb_t putc_cb);
131static int mxml_write_ws(mxml_node_t *node, void *p,
132 mxml_save_cb_t cb, int ws,
133 int col, _mxml_putc_cb_t putc_cb);
134
135
136/*
137 * 'mxmlLoadFd()' - Load a file descriptor into an XML node tree.
138 *
139 * The nodes in the specified file are added to the specified top node.
140 * If no top node is provided, the XML file MUST be well-formed with a
141 * single parent node like <?xml> for the entire file. The callback
142 * function returns the value type that should be used for child nodes.
143 * If MXML_NO_CALLBACK is specified then all child nodes will be either
144 * MXML_ELEMENT or MXML_TEXT nodes.
145 *
146 * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,
147 * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading
148 * child nodes of the specified type.
149 */
150
151mxml_node_t * /* O - First node or NULL if the file could not be read. */
152mxmlLoadFd(mxml_node_t *top, /* I - Top node */
153 int fd, /* I - File descriptor to read from */
154 mxml_load_cb_t cb) /* I - Callback function or MXML_NO_CALLBACK */
155{
156 _mxml_fdbuf_t buf; /* File descriptor buffer */
157
158
159 /*
160 * Initialize the file descriptor buffer...
161 */
162
163 buf.fd = fd;
164 buf.current = buf.buffer;
165 buf.end = buf.buffer;
166
167 /*
168 * Read the XML data...
169 */
170
171 return (mxml_load_data(top, &buf, cb, mxml_fd_getc, MXML_NO_CALLBACK, NULL));
172}
173
174
175/*
176 * 'mxmlLoadFile()' - Load a file into an XML node tree.
177 *
178 * The nodes in the specified file are added to the specified top node.
179 * If no top node is provided, the XML file MUST be well-formed with a
180 * single parent node like <?xml> for the entire file. The callback
181 * function returns the value type that should be used for child nodes.
182 * If MXML_NO_CALLBACK is specified then all child nodes will be either
183 * MXML_ELEMENT or MXML_TEXT nodes.
184 *
185 * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,
186 * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading
187 * child nodes of the specified type.
188 */
189
190mxml_node_t * /* O - First node or NULL if the file could not be read. */
191mxmlLoadFile(mxml_node_t *top, /* I - Top node */
192 FILE *fp, /* I - File to read from */
193 mxml_load_cb_t cb) /* I - Callback function or MXML_NO_CALLBACK */
194{
195 /*
196 * Read the XML data...
197 */
198
199 return (mxml_load_data(top, fp, cb, mxml_file_getc, MXML_NO_CALLBACK, NULL));
200}
201
202
203/*
204 * 'mxmlLoadString()' - Load a string into an XML node tree.
205 *
206 * The nodes in the specified string are added to the specified top node.
207 * If no top node is provided, the XML string MUST be well-formed with a
208 * single parent node like <?xml> for the entire string. The callback
209 * function returns the value type that should be used for child nodes.
210 * If MXML_NO_CALLBACK is specified then all child nodes will be either
211 * MXML_ELEMENT or MXML_TEXT nodes.
212 *
213 * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,
214 * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading
215 * child nodes of the specified type.
216 */
217
218mxml_node_t * /* O - First node or NULL if the string has errors. */
219mxmlLoadString(mxml_node_t *top, /* I - Top node */
220 const char *s, /* I - String to load */
221 mxml_load_cb_t cb) /* I - Callback function or MXML_NO_CALLBACK */
222{
223 /*
224 * Read the XML data...
225 */
226
227 return (mxml_load_data(top, (void *)&s, cb, mxml_string_getc, MXML_NO_CALLBACK,
228 NULL));
229}
230
231
232/*
233 * 'mxmlSaveAllocString()' - Save an XML tree to an allocated string.
234 *
235 * This function returns a pointer to a string containing the textual
236 * representation of the XML node tree. The string should be freed
237 * using the free() function when you are done with it. NULL is returned
238 * if the node would produce an empty string or if the string cannot be
239 * allocated.
240 *
241 * The callback argument specifies a function that returns a whitespace
242 * string or NULL before and after each element. If MXML_NO_CALLBACK
243 * is specified, whitespace will only be added before MXML_TEXT nodes
244 * with leading whitespace and before attribute names inside opening
245 * element tags.
246 */
247
248char * /* O - Allocated string or NULL */
249mxmlSaveAllocString(
250 mxml_node_t *node, /* I - Node to write */
251 mxml_save_cb_t cb) /* I - Whitespace callback or MXML_NO_CALLBACK */
252{
253 int bytes; /* Required bytes */
254 char buffer[8192]; /* Temporary buffer */
255 char *s; /* Allocated string */
256
257
258 /*
259 * Write the node to the temporary buffer...
260 */
261
262 bytes = mxmlSaveString(node, buffer, sizeof(buffer), cb);
263
264 if (bytes <= 0)
265 return (NULL);
266
267 if (bytes < (int)(sizeof(buffer) - 1))
268 {
269 /*
270 * Node fit inside the buffer, so just duplicate that string and
271 * return...
272 */
273
274 return (strdup(buffer));
275 }
276
277 /*
278 * Allocate a buffer of the required size and save the node to the
279 * new buffer...
280 */
281
282 if ((s = malloc(bytes + 1)) == NULL)
283 return (NULL);
284
285 mxmlSaveString(node, s, bytes + 1, cb);
286
287 /*
288 * Return the allocated string...
289 */
290
291 return (s);
292}
293
294
295/*
296 * 'mxmlSaveFd()' - Save an XML tree to a file descriptor.
297 *
298 * The callback argument specifies a function that returns a whitespace
299 * string or NULL before and after each element. If MXML_NO_CALLBACK
300 * is specified, whitespace will only be added before MXML_TEXT nodes
301 * with leading whitespace and before attribute names inside opening
302 * element tags.
303 */
304
305int /* O - 0 on success, -1 on error. */
306mxmlSaveFd(mxml_node_t *node, /* I - Node to write */
307 int fd, /* I - File descriptor to write to */
308 mxml_save_cb_t cb) /* I - Whitespace callback or MXML_NO_CALLBACK */
309{
310 int col; /* Final column */
311 _mxml_fdbuf_t buf; /* File descriptor buffer */
312 _mxml_global_t *global = _mxml_global();
313 /* Global data */
314
315
316 /*
317 * Initialize the file descriptor buffer...
318 */
319
320 buf.fd = fd;
321 buf.current = buf.buffer;
322 buf.end = buf.buffer + sizeof(buf.buffer);
323
324 /*
325 * Write the node...
326 */
327
328 if ((col = mxml_write_node(node, &buf, cb, 0, mxml_fd_putc, global)) < 0)
329 return (-1);
330
331 if (col > 0)
332 if (mxml_fd_putc('\n', &buf) < 0)
333 return (-1);
334
335 /*
336 * Flush and return...
337 */
338
339 return (mxml_fd_write(&buf));
340}
341
342
343/*
344 * 'mxmlSaveFile()' - Save an XML tree to a file.
345 *
346 * The callback argument specifies a function that returns a whitespace
347 * string or NULL before and after each element. If MXML_NO_CALLBACK
348 * is specified, whitespace will only be added before MXML_TEXT nodes
349 * with leading whitespace and before attribute names inside opening
350 * element tags.
351 */
352
353int /* O - 0 on success, -1 on error. */
354mxmlSaveFile(mxml_node_t *node, /* I - Node to write */
355 FILE *fp, /* I - File to write to */
356 mxml_save_cb_t cb) /* I - Whitespace callback or MXML_NO_CALLBACK */
357{
358 int col; /* Final column */
359 _mxml_global_t *global = _mxml_global();
360 /* Global data */
361
362
363 /*
364 * Write the node...
365 */
366
367 if ((col = mxml_write_node(node, fp, cb, 0, mxml_file_putc, global)) < 0)
368 return (-1);
369
370 if (col > 0)
371 if (putc('\n', fp) < 0)
372 return (-1);
373
374 /*
375 * Return 0 (success)...
376 */
377
378 return (0);
379}
380
381
382/*
383 * 'mxmlSaveString()' - Save an XML node tree to a string.
384 *
385 * This function returns the total number of bytes that would be
386 * required for the string but only copies (bufsize - 1) characters
387 * into the specified buffer.
388 *
389 * The callback argument specifies a function that returns a whitespace
390 * string or NULL before and after each element. If MXML_NO_CALLBACK
391 * is specified, whitespace will only be added before MXML_TEXT nodes
392 * with leading whitespace and before attribute names inside opening
393 * element tags.
394 */
395
396int /* O - Size of string */
397mxmlSaveString(mxml_node_t *node, /* I - Node to write */
398 char *buffer, /* I - String buffer */
399 int bufsize, /* I - Size of string buffer */
400 mxml_save_cb_t cb) /* I - Whitespace callback or MXML_NO_CALLBACK */
401{
402 int col; /* Final column */
403 char *ptr[2]; /* Pointers for putc_cb */
404 _mxml_global_t *global = _mxml_global();
405 /* Global data */
406
407
408 /*
409 * Write the node...
410 */
411
412 ptr[0] = buffer;
413 ptr[1] = buffer + bufsize;
414
415 if ((col = mxml_write_node(node, ptr, cb, 0, mxml_string_putc, global)) < 0)
416 return (-1);
417
418 if (col > 0)
419 mxml_string_putc('\n', ptr);
420
421 /*
422 * Nul-terminate the buffer...
423 */
424
425 if (ptr[0] >= ptr[1])
426 buffer[bufsize - 1] = '\0';
427 else
428 ptr[0][0] = '\0';
429
430 /*
431 * Return the number of characters...
432 */
433
434 return (ptr[0] - buffer);
435}
436
437
438/*
439 * 'mxmlSAXLoadFd()' - Load a file descriptor into an XML node tree
440 * using a SAX callback.
441 *
442 * The nodes in the specified file are added to the specified top node.
443 * If no top node is provided, the XML file MUST be well-formed with a
444 * single parent node like <?xml> for the entire file. The callback
445 * function returns the value type that should be used for child nodes.
446 * If MXML_NO_CALLBACK is specified then all child nodes will be either
447 * MXML_ELEMENT or MXML_TEXT nodes.
448 *
449 * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,
450 * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading
451 * child nodes of the specified type.
452 *
453 * The SAX callback must call mxmlRetain() for any nodes that need to
454 * be kept for later use. Otherwise, nodes are deleted when the parent
455 * node is closed or after each data, comment, CDATA, or directive node.
456 *
457 * @since Mini-XML 2.3@
458 */
459
460mxml_node_t * /* O - First node or NULL if the file could not be read. */
461mxmlSAXLoadFd(mxml_node_t *top, /* I - Top node */
462 int fd, /* I - File descriptor to read from */
463 mxml_load_cb_t cb, /* I - Callback function or MXML_NO_CALLBACK */
464 mxml_sax_cb_t sax_cb, /* I - SAX callback or MXML_NO_CALLBACK */
465 void *sax_data) /* I - SAX user data */
466{
467 _mxml_fdbuf_t buf; /* File descriptor buffer */
468
469
470 /*
471 * Initialize the file descriptor buffer...
472 */
473
474 buf.fd = fd;
475 buf.current = buf.buffer;
476 buf.end = buf.buffer;
477
478 /*
479 * Read the XML data...
480 */
481
482 return (mxml_load_data(top, &buf, cb, mxml_fd_getc, sax_cb, sax_data));
483}
484
485
486/*
487 * 'mxmlSAXLoadFile()' - Load a file into an XML node tree
488 * using a SAX callback.
489 *
490 * The nodes in the specified file are added to the specified top node.
491 * If no top node is provided, the XML file MUST be well-formed with a
492 * single parent node like <?xml> for the entire file. The callback
493 * function returns the value type that should be used for child nodes.
494 * If MXML_NO_CALLBACK is specified then all child nodes will be either
495 * MXML_ELEMENT or MXML_TEXT nodes.
496 *
497 * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,
498 * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading
499 * child nodes of the specified type.
500 *
501 * The SAX callback must call mxmlRetain() for any nodes that need to
502 * be kept for later use. Otherwise, nodes are deleted when the parent
503 * node is closed or after each data, comment, CDATA, or directive node.
504 *
505 * @since Mini-XML 2.3@
506 */
507
508mxml_node_t * /* O - First node or NULL if the file could not be read. */
509mxmlSAXLoadFile(
510 mxml_node_t *top, /* I - Top node */
511 FILE *fp, /* I - File to read from */
512 mxml_load_cb_t cb, /* I - Callback function or MXML_NO_CALLBACK */
513 mxml_sax_cb_t sax_cb, /* I - SAX callback or MXML_NO_CALLBACK */
514 void *sax_data) /* I - SAX user data */
515{
516 /*
517 * Read the XML data...
518 */
519
520 return (mxml_load_data(top, fp, cb, mxml_file_getc, sax_cb, sax_data));
521}
522
523
524/*
525 * 'mxmlSAXLoadString()' - Load a string into an XML node tree
526 * using a SAX callback.
527 *
528 * The nodes in the specified string are added to the specified top node.
529 * If no top node is provided, the XML string MUST be well-formed with a
530 * single parent node like <?xml> for the entire string. The callback
531 * function returns the value type that should be used for child nodes.
532 * If MXML_NO_CALLBACK is specified then all child nodes will be either
533 * MXML_ELEMENT or MXML_TEXT nodes.
534 *
535 * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,
536 * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading
537 * child nodes of the specified type.
538 *
539 * The SAX callback must call mxmlRetain() for any nodes that need to
540 * be kept for later use. Otherwise, nodes are deleted when the parent
541 * node is closed or after each data, comment, CDATA, or directive node.
542 *
543 * @since Mini-XML 2.3@
544 */
545
546mxml_node_t * /* O - First node or NULL if the string has errors. */
547mxmlSAXLoadString(
548 mxml_node_t *top, /* I - Top node */
549 const char *s, /* I - String to load */
550 mxml_load_cb_t cb, /* I - Callback function or MXML_NO_CALLBACK */
551 mxml_sax_cb_t sax_cb, /* I - SAX callback or MXML_NO_CALLBACK */
552 void *sax_data) /* I - SAX user data */
553{
554 /*
555 * Read the XML data...
556 */
557
558 return (mxml_load_data(top, (void *)&s, cb, mxml_string_getc, sax_cb, sax_data));
559}
560
561
562/*
563 * 'mxmlSetCustomHandlers()' - Set the handling functions for custom data.
564 *
565 * The load function accepts a node pointer and a data string and must
566 * return 0 on success and non-zero on error.
567 *
568 * The save function accepts a node pointer and must return a malloc'd
569 * string on success and NULL on error.
570 *
571 */
572
573void
574mxmlSetCustomHandlers(
575 mxml_custom_load_cb_t load, /* I - Load function */
576 mxml_custom_save_cb_t save) /* I - Save function */
577{
578 _mxml_global_t *global = _mxml_global();
579 /* Global data */
580
581
582 global->custom_load_cb = load;
583 global->custom_save_cb = save;
584}
585
586
587/*
588 * 'mxmlSetErrorCallback()' - Set the error message callback.
589 */
590
591void
592mxmlSetErrorCallback(mxml_error_cb_t cb)/* I - Error callback function */
593{
594 _mxml_global_t *global = _mxml_global();
595 /* Global data */
596
597
598 global->error_cb = cb;
599}
600
601
602/*
603 * 'mxmlSetWrapMargin()' - Set the wrap margin when saving XML data.
604 *
605 * Wrapping is disabled when "column" is 0.
606 *
607 * @since Mini-XML 2.3@
608 */
609
610void
611mxmlSetWrapMargin(int column) /* I - Column for wrapping, 0 to disable wrapping */
612{
613 _mxml_global_t *global = _mxml_global();
614 /* Global data */
615
616
617 global->wrap = column;
618}
619
620
621/*
622 * 'mxml_add_char()' - Add a character to a buffer, expanding as needed.
623 */
624
625static int /* O - 0 on success, -1 on error */
626mxml_add_char(int ch, /* I - Character to add */
627 char **bufptr, /* IO - Current position in buffer */
628 char **buffer, /* IO - Current buffer */
629 int *bufsize) /* IO - Current buffer size */
630{
631 char *newbuffer; /* New buffer value */
632
633
634 if (*bufptr >= (*buffer + *bufsize - 4))
635 {
636 /*
637 * Increase the size of the buffer...
638 */
639
640 if (*bufsize < 1024)
641 (*bufsize) *= 2;
642 else
643 (*bufsize) += 1024;
644
645 if ((newbuffer = realloc(*buffer, *bufsize)) == NULL)
646 {
647 free(*buffer);
648
649 mxml_error("Unable to expand string buffer to %d bytes!", *bufsize);
650
651 return (-1);
652 }
653
654 *bufptr = newbuffer + (*bufptr - *buffer);
655 *buffer = newbuffer;
656 }
657
658 if (ch < 0x80)
659 {
660 /*
661 * Single byte ASCII...
662 */
663
664 *(*bufptr)++ = ch;
665 }
666 else if (ch < 0x800)
667 {
668 /*
669 * Two-byte UTF-8...
670 */
671
672 *(*bufptr)++ = 0xc0 | (ch >> 6);
673 *(*bufptr)++ = 0x80 | (ch & 0x3f);
674 }
675 else if (ch < 0x10000)
676 {
677 /*
678 * Three-byte UTF-8...
679 */
680
681 *(*bufptr)++ = 0xe0 | (ch >> 12);
682 *(*bufptr)++ = 0x80 | ((ch >> 6) & 0x3f);
683 *(*bufptr)++ = 0x80 | (ch & 0x3f);
684 }
685 else
686 {
687 /*
688 * Four-byte UTF-8...
689 */
690
691 *(*bufptr)++ = 0xf0 | (ch >> 18);
692 *(*bufptr)++ = 0x80 | ((ch >> 12) & 0x3f);
693 *(*bufptr)++ = 0x80 | ((ch >> 6) & 0x3f);
694 *(*bufptr)++ = 0x80 | (ch & 0x3f);
695 }
696
697 return (0);
698}
699
700
701/*
702 * 'mxml_fd_getc()' - Read a character from a file descriptor.
703 */
704
705static int /* O - Character or EOF */
706mxml_fd_getc(void *p, /* I - File descriptor buffer */
707 int *encoding) /* IO - Encoding */
708{
709 _mxml_fdbuf_t *buf; /* File descriptor buffer */
710 int ch, /* Current character */
711 temp; /* Temporary character */
712
713
714 /*
715 * Grab the next character in the buffer...
716 */
717
718 buf = (_mxml_fdbuf_t *)p;
719
720 if (buf->current >= buf->end)
721 if (mxml_fd_read(buf) < 0)
722 return (EOF);
723
724 ch = *(buf->current)++;
725
726 switch (*encoding)
727 {
728 case ENCODE_UTF8 :
729 /*
730 * Got a UTF-8 character; convert UTF-8 to Unicode and return...
731 */
732
733 if (!(ch & 0x80))
734 {
735#if DEBUG > 1
736 printf("mxml_fd_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
737#endif /* DEBUG > 1 */
738
739 if (mxml_bad_char(ch))
740 {
741 mxml_error("Bad control character 0x%02x not allowed by XML standard!",
742 ch);
743 return (EOF);
744 }
745
746 return (ch);
747 }
748 else if (ch == 0xfe)
749 {
750 /*
751 * UTF-16 big-endian BOM?
752 */
753
754 if (buf->current >= buf->end)
755 if (mxml_fd_read(buf) < 0)
756 return (EOF);
757
758 ch = *(buf->current)++;
759
760 if (ch != 0xff)
761 return (EOF);
762
763 *encoding = ENCODE_UTF16BE;
764
765 return (mxml_fd_getc(p, encoding));
766 }
767 else if (ch == 0xff)
768 {
769 /*
770 * UTF-16 little-endian BOM?
771 */
772
773 if (buf->current >= buf->end)
774 if (mxml_fd_read(buf) < 0)
775 return (EOF);
776
777 ch = *(buf->current)++;
778
779 if (ch != 0xfe)
780 return (EOF);
781
782 *encoding = ENCODE_UTF16LE;
783
784 return (mxml_fd_getc(p, encoding));
785 }
786 else if ((ch & 0xe0) == 0xc0)
787 {
788 /*
789 * Two-byte value...
790 */
791
792 if (buf->current >= buf->end)
793 if (mxml_fd_read(buf) < 0)
794 return (EOF);
795
796 temp = *(buf->current)++;
797
798 if ((temp & 0xc0) != 0x80)
799 return (EOF);
800
801 ch = ((ch & 0x1f) << 6) | (temp & 0x3f);
802
803 if (ch < 0x80)
804 {
805 mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
806 return (EOF);
807 }
808 }
809 else if ((ch & 0xf0) == 0xe0)
810 {
811 /*
812 * Three-byte value...
813 */
814
815 if (buf->current >= buf->end)
816 if (mxml_fd_read(buf) < 0)
817 return (EOF);
818
819 temp = *(buf->current)++;
820
821 if ((temp & 0xc0) != 0x80)
822 return (EOF);
823
824 ch = ((ch & 0x0f) << 6) | (temp & 0x3f);
825
826 if (buf->current >= buf->end)
827 if (mxml_fd_read(buf) < 0)
828 return (EOF);
829
830 temp = *(buf->current)++;
831
832 if ((temp & 0xc0) != 0x80)
833 return (EOF);
834
835 ch = (ch << 6) | (temp & 0x3f);
836
837 if (ch < 0x800)
838 {
839 mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
840 return (EOF);
841 }
842
843 /*
844 * Ignore (strip) Byte Order Mark (BOM)...
845 */
846
847 if (ch == 0xfeff)
848 return (mxml_fd_getc(p, encoding));
849 }
850 else if ((ch & 0xf8) == 0xf0)
851 {
852 /*
853 * Four-byte value...
854 */
855
856 if (buf->current >= buf->end)
857 if (mxml_fd_read(buf) < 0)
858 return (EOF);
859
860 temp = *(buf->current)++;
861
862 if ((temp & 0xc0) != 0x80)
863 return (EOF);
864
865 ch = ((ch & 0x07) << 6) | (temp & 0x3f);
866
867 if (buf->current >= buf->end)
868 if (mxml_fd_read(buf) < 0)
869 return (EOF);
870
871 temp = *(buf->current)++;
872
873 if ((temp & 0xc0) != 0x80)
874 return (EOF);
875
876 ch = (ch << 6) | (temp & 0x3f);
877
878 if (buf->current >= buf->end)
879 if (mxml_fd_read(buf) < 0)
880 return (EOF);
881
882 temp = *(buf->current)++;
883
884 if ((temp & 0xc0) != 0x80)
885 return (EOF);
886
887 ch = (ch << 6) | (temp & 0x3f);
888
889 if (ch < 0x10000)
890 {
891 mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
892 return (EOF);
893 }
894 }
895 else
896 return (EOF);
897 break;
898
899 case ENCODE_UTF16BE :
900 /*
901 * Read UTF-16 big-endian char...
902 */
903
904 if (buf->current >= buf->end)
905 if (mxml_fd_read(buf) < 0)
906 return (EOF);
907
908 temp = *(buf->current)++;
909
910 ch = (ch << 8) | temp;
911
912 if (mxml_bad_char(ch))
913 {
914 mxml_error("Bad control character 0x%02x not allowed by XML standard!",
915 ch);
916 return (EOF);
917 }
918 else if (ch >= 0xd800 && ch <= 0xdbff)
919 {
920 /*
921 * Multi-word UTF-16 char...
922 */
923
924 int lch;
925
926 if (buf->current >= buf->end)
927 if (mxml_fd_read(buf) < 0)
928 return (EOF);
929
930 lch = *(buf->current)++;
931
932 if (buf->current >= buf->end)
933 if (mxml_fd_read(buf) < 0)
934 return (EOF);
935
936 temp = *(buf->current)++;
937
938 lch = (lch << 8) | temp;
939
940 if (lch < 0xdc00 || lch >= 0xdfff)
941 return (EOF);
942
943 ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
944 }
945 break;
946
947 case ENCODE_UTF16LE :
948 /*
949 * Read UTF-16 little-endian char...
950 */
951
952 if (buf->current >= buf->end)
953 if (mxml_fd_read(buf) < 0)
954 return (EOF);
955
956 temp = *(buf->current)++;
957
958 ch |= (temp << 8);
959
960 if (mxml_bad_char(ch))
961 {
962 mxml_error("Bad control character 0x%02x not allowed by XML standard!",
963 ch);
964 return (EOF);
965 }
966 else if (ch >= 0xd800 && ch <= 0xdbff)
967 {
968 /*
969 * Multi-word UTF-16 char...
970 */
971
972 int lch;
973
974 if (buf->current >= buf->end)
975 if (mxml_fd_read(buf) < 0)
976 return (EOF);
977
978 lch = *(buf->current)++;
979
980 if (buf->current >= buf->end)
981 if (mxml_fd_read(buf) < 0)
982 return (EOF);
983
984 temp = *(buf->current)++;
985
986 lch |= (temp << 8);
987
988 if (lch < 0xdc00 || lch >= 0xdfff)
989 return (EOF);
990
991 ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
992 }
993 break;
994 }
995
996#if DEBUG > 1
997 printf("mxml_fd_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
998#endif /* DEBUG > 1 */
999
1000 return (ch);
1001}
1002
1003
1004/*
1005 * 'mxml_fd_putc()' - Write a character to a file descriptor.
1006 */
1007
1008static int /* O - 0 on success, -1 on error */
1009mxml_fd_putc(int ch, /* I - Character */
1010 void *p) /* I - File descriptor buffer */
1011{
1012 _mxml_fdbuf_t *buf; /* File descriptor buffer */
1013
1014
1015 /*
1016 * Flush the write buffer as needed...
1017 */
1018
1019 buf = (_mxml_fdbuf_t *)p;
1020
1021 if (buf->current >= buf->end)
1022 if (mxml_fd_write(buf) < 0)
1023 return (-1);
1024
1025 *(buf->current)++ = ch;
1026
1027 /*
1028 * Return successfully...
1029 */
1030
1031 return (0);
1032}
1033
1034
1035/*
1036 * 'mxml_fd_read()' - Read a buffer of data from a file descriptor.
1037 */
1038
1039static int /* O - 0 on success, -1 on error */
1040mxml_fd_read(_mxml_fdbuf_t *buf) /* I - File descriptor buffer */
1041{
1042 int bytes; /* Bytes read... */
1043
1044
1045 /*
1046 * Range check input...
1047 */
1048
1049 if (!buf)
1050 return (-1);
1051
1052 /*
1053 * Read from the file descriptor...
1054 */
1055
1056 while ((bytes = read(buf->fd, buf->buffer, sizeof(buf->buffer))) < 0)
1057#ifdef EINTR
1058 if (errno != EAGAIN && errno != EINTR)
1059#else
1060 if (errno != EAGAIN)
1061#endif /* EINTR */
1062 return (-1);
1063
1064 if (bytes == 0)
1065 return (-1);
1066
1067 /*
1068 * Update the pointers and return success...
1069 */
1070
1071 buf->current = buf->buffer;
1072 buf->end = buf->buffer + bytes;
1073
1074 return (0);
1075}
1076
1077
1078/*
1079 * 'mxml_fd_write()' - Write a buffer of data to a file descriptor.
1080 */
1081
1082static int /* O - 0 on success, -1 on error */
1083mxml_fd_write(_mxml_fdbuf_t *buf) /* I - File descriptor buffer */
1084{
1085 int bytes; /* Bytes written */
1086 unsigned char *ptr; /* Pointer into buffer */
1087
1088
1089 /*
1090 * Range check...
1091 */
1092
1093 if (!buf)
1094 return (-1);
1095
1096 /*
1097 * Return 0 if there is nothing to write...
1098 */
1099
1100 if (buf->current == buf->buffer)
1101 return (0);
1102
1103 /*
1104 * Loop until we have written everything...
1105 */
1106
1107 for (ptr = buf->buffer; ptr < buf->current; ptr += bytes)
1108 if ((bytes = write(buf->fd, ptr, buf->current - ptr)) < 0)
1109 return (-1);
1110
1111 /*
1112 * All done, reset pointers and return success...
1113 */
1114
1115 buf->current = buf->buffer;
1116
1117 return (0);
1118}
1119
1120
1121/*
1122 * 'mxml_file_getc()' - Get a character from a file.
1123 */
1124
1125static int /* O - Character or EOF */
1126mxml_file_getc(void *p, /* I - Pointer to file */
1127 int *encoding) /* IO - Encoding */
1128{
1129 int ch, /* Character from file */
1130 temp; /* Temporary character */
1131 FILE *fp; /* Pointer to file */
1132
1133
1134 /*
1135 * Read a character from the file and see if it is EOF or ASCII...
1136 */
1137
1138 fp = (FILE *)p;
1139 ch = getc(fp);
1140
1141 if (ch == EOF)
1142 return (EOF);
1143
1144 switch (*encoding)
1145 {
1146 case ENCODE_UTF8 :
1147 /*
1148 * Got a UTF-8 character; convert UTF-8 to Unicode and return...
1149 */
1150
1151 if (!(ch & 0x80))
1152 {
1153 if (mxml_bad_char(ch))
1154 {
1155 mxml_error("Bad control character 0x%02x not allowed by XML standard!",
1156 ch);
1157 return (EOF);
1158 }
1159
1160#if DEBUG > 1
1161 printf("mxml_file_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
1162#endif /* DEBUG > 1 */
1163
1164 return (ch);
1165 }
1166 else if (ch == 0xfe)
1167 {
1168 /*
1169 * UTF-16 big-endian BOM?
1170 */
1171
1172 ch = getc(fp);
1173 if (ch != 0xff)
1174 return (EOF);
1175
1176 *encoding = ENCODE_UTF16BE;
1177
1178 return (mxml_file_getc(p, encoding));
1179 }
1180 else if (ch == 0xff)
1181 {
1182 /*
1183 * UTF-16 little-endian BOM?
1184 */
1185
1186 ch = getc(fp);
1187 if (ch != 0xfe)
1188 return (EOF);
1189
1190 *encoding = ENCODE_UTF16LE;
1191
1192 return (mxml_file_getc(p, encoding));
1193 }
1194 else if ((ch & 0xe0) == 0xc0)
1195 {
1196 /*
1197 * Two-byte value...
1198 */
1199
1200 if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)
1201 return (EOF);
1202
1203 ch = ((ch & 0x1f) << 6) | (temp & 0x3f);
1204
1205 if (ch < 0x80)
1206 {
1207 mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
1208 return (EOF);
1209 }
1210 }
1211 else if ((ch & 0xf0) == 0xe0)
1212 {
1213 /*
1214 * Three-byte value...
1215 */
1216
1217 if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)
1218 return (EOF);
1219
1220 ch = ((ch & 0x0f) << 6) | (temp & 0x3f);
1221
1222 if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)
1223 return (EOF);
1224
1225 ch = (ch << 6) | (temp & 0x3f);
1226
1227 if (ch < 0x800)
1228 {
1229 mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
1230 return (EOF);
1231 }
1232
1233 /*
1234 * Ignore (strip) Byte Order Mark (BOM)...
1235 */
1236
1237 if (ch == 0xfeff)
1238 return (mxml_file_getc(p, encoding));
1239 }
1240 else if ((ch & 0xf8) == 0xf0)
1241 {
1242 /*
1243 * Four-byte value...
1244 */
1245
1246 if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)
1247 return (EOF);
1248
1249 ch = ((ch & 0x07) << 6) | (temp & 0x3f);
1250
1251 if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)
1252 return (EOF);
1253
1254 ch = (ch << 6) | (temp & 0x3f);
1255
1256 if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)
1257 return (EOF);
1258
1259 ch = (ch << 6) | (temp & 0x3f);
1260
1261 if (ch < 0x10000)
1262 {
1263 mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
1264 return (EOF);
1265 }
1266 }
1267 else
1268 return (EOF);
1269 break;
1270
1271 case ENCODE_UTF16BE :
1272 /*
1273 * Read UTF-16 big-endian char...
1274 */
1275
1276 ch = (ch << 8) | getc(fp);
1277
1278 if (mxml_bad_char(ch))
1279 {
1280 mxml_error("Bad control character 0x%02x not allowed by XML standard!",
1281 ch);
1282 return (EOF);
1283 }
1284 else if (ch >= 0xd800 && ch <= 0xdbff)
1285 {
1286 /*
1287 * Multi-word UTF-16 char...
1288 */
1289
1290 int lch = (getc(fp) << 8);
1291 lch |= getc(fp);
1292
1293 if (lch < 0xdc00 || lch >= 0xdfff)
1294 return (EOF);
1295
1296 ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
1297 }
1298 break;
1299
1300 case ENCODE_UTF16LE :
1301 /*
1302 * Read UTF-16 little-endian char...
1303 */
1304
1305 ch |= (getc(fp) << 8);
1306
1307 if (mxml_bad_char(ch))
1308 {
1309 mxml_error("Bad control character 0x%02x not allowed by XML standard!",
1310 ch);
1311 return (EOF);
1312 }
1313 else if (ch >= 0xd800 && ch <= 0xdbff)
1314 {
1315 /*
1316 * Multi-word UTF-16 char...
1317 */
1318
1319 int lch = getc(fp);
1320 lch |= (getc(fp) << 8);
1321
1322 if (lch < 0xdc00 || lch >= 0xdfff)
1323 return (EOF);
1324
1325 ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
1326 }
1327 break;
1328 }
1329
1330#if DEBUG > 1
1331 printf("mxml_file_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
1332#endif /* DEBUG > 1 */
1333
1334 return (ch);
1335}
1336
1337
1338/*
1339 * 'mxml_file_putc()' - Write a character to a file.
1340 */
1341
1342static int /* O - 0 on success, -1 on failure */
1343mxml_file_putc(int ch, /* I - Character to write */
1344 void *p) /* I - Pointer to file */
1345{
1346 return (putc(ch, (FILE *)p) == EOF ? -1 : 0);
1347}
1348
1349
1350/*
1351 * 'mxml_get_entity()' - Get the character corresponding to an entity...
1352 */
1353
1354static int /* O - Character value or EOF on error */
1355mxml_get_entity(mxml_node_t *parent, /* I - Parent node */
1356 void *p, /* I - Pointer to source */
1357 int *encoding, /* IO - Character encoding */
1358 int (*getc_cb)(void *, int *))
1359 /* I - Get character function */
1360{
1361 int ch; /* Current character */
1362 char entity[64], /* Entity string */
1363 *entptr; /* Pointer into entity */
1364
1365
1366 entptr = entity;
1367
1368 while ((ch = (*getc_cb)(p, encoding)) != EOF)
1369 if (ch > 126 || (!isalnum(ch) && ch != '#'))
1370 break;
1371 else if (entptr < (entity + sizeof(entity) - 1))
1372 *entptr++ = ch;
1373 else
1374 {
1375 mxml_error("Entity name too long under parent <%s>!",
1376 parent ? parent->value.element.name : "null");
1377 break;
1378 }
1379
1380 *entptr = '\0';
1381
1382 if (ch != ';')
1383 {
1384 mxml_error("Character entity \"%s\" not terminated under parent <%s>!",
1385 entity, parent ? parent->value.element.name : "null");
1386 return (EOF);
1387 }
1388
1389 if (entity[0] == '#')
1390 {
1391 if (entity[1] == 'x')
1392 ch = strtol(entity + 2, NULL, 16);
1393 else
1394 ch = strtol(entity + 1, NULL, 10);
1395 }
1396 else if ((ch = mxmlEntityGetValue(entity)) < 0)
1397 mxml_error("Entity name \"%s;\" not supported under parent <%s>!",
1398 entity, parent ? parent->value.element.name : "null");
1399
1400 if (mxml_bad_char(ch))
1401 {
1402 mxml_error("Bad control character 0x%02x under parent <%s> not allowed by XML standard!",
1403 ch, parent ? parent->value.element.name : "null");
1404 return (EOF);
1405 }
1406
1407 return (ch);
1408}
1409
1410
1411/*
1412 * 'mxml_load_data()' - Load data into an XML node tree.
1413 */
1414
1415static mxml_node_t * /* O - First node or NULL if the file could not be read. */
1416mxml_load_data(
1417 mxml_node_t *top, /* I - Top node */
1418 void *p, /* I - Pointer to data */
1419 mxml_load_cb_t cb, /* I - Callback function or MXML_NO_CALLBACK */
1420 _mxml_getc_cb_t getc_cb, /* I - Read function */
1421 mxml_sax_cb_t sax_cb, /* I - SAX callback or MXML_NO_CALLBACK */
1422 void *sax_data) /* I - SAX user data */
1423{
1424 mxml_node_t *node, /* Current node */
1425 *first, /* First node added */
1426 *parent; /* Current parent node */
1427 int ch, /* Character from file */
1428 whitespace; /* Non-zero if whitespace seen */
1429 char *buffer, /* String buffer */
1430 *bufptr; /* Pointer into buffer */
1431 int bufsize; /* Size of buffer */
1432 mxml_type_t type; /* Current node type */
1433 int encoding; /* Character encoding */
1434 _mxml_global_t *global = _mxml_global();
1435 /* Global data */
1436 static const char * const types[] = /* Type strings... */
1437 {
1438 "MXML_ELEMENT", /* XML element with attributes */
1439 "MXML_INTEGER", /* Integer value */
1440 "MXML_OPAQUE", /* Opaque string */
1441 "MXML_REAL", /* Real value */
1442 "MXML_TEXT", /* Text fragment */
1443 "MXML_CUSTOM" /* Custom data */
1444 };
1445
1446
1447 /*
1448 * Read elements and other nodes from the file...
1449 */
1450
1451 if ((buffer = malloc(64)) == NULL)
1452 {
1453 mxml_error("Unable to allocate string buffer!");
1454 return (NULL);
1455 }
1456
1457 bufsize = 64;
1458 bufptr = buffer;
1459 parent = top;
1460 first = NULL;
1461 whitespace = 0;
1462 encoding = ENCODE_UTF8;
1463
1464 if (cb && parent)
1465 type = (*cb)(parent);
1466 else
1467 type = MXML_TEXT;
1468
1469 while ((ch = (*getc_cb)(p, &encoding)) != EOF)
1470 {
1471 if ((ch == '<' ||
1472 (mxml_isspace(ch) && type != MXML_OPAQUE && type != MXML_CUSTOM)) &&
1473 bufptr > buffer)
1474 {
1475 /*
1476 * Add a new value node...
1477 */
1478
1479 *bufptr = '\0';
1480
1481 switch (type)
1482 {
1483 case MXML_INTEGER :
1484 node = mxmlNewInteger(parent, strtol(buffer, &bufptr, 0));
1485 break;
1486
1487 case MXML_OPAQUE :
1488 node = mxmlNewOpaque(parent, buffer);
1489 break;
1490
1491 case MXML_REAL :
1492 node = mxmlNewReal(parent, strtod(buffer, &bufptr));
1493 break;
1494
1495 case MXML_TEXT :
1496 node = mxmlNewText(parent, whitespace, buffer);
1497 break;
1498
1499 case MXML_CUSTOM :
1500 if (global->custom_load_cb)
1501 {
1502 /*
1503 * Use the callback to fill in the custom data...
1504 */
1505
1506 node = mxmlNewCustom(parent, NULL, NULL);
1507
1508 if ((*global->custom_load_cb)(node, buffer))
1509 {
1510 mxml_error("Bad custom value '%s' in parent <%s>!",
1511 buffer, parent ? parent->value.element.name : "null");
1512 mxmlDelete(node);
1513 node = NULL;
1514 }
1515 break;
1516 }
1517
1518 default : /* Ignore... */
1519 node = NULL;
1520 break;
1521 }
1522
1523 if (*bufptr)
1524 {
1525 /*
1526 * Bad integer/real number value...
1527 */
1528
1529 mxml_error("Bad %s value '%s' in parent <%s>!",
1530 type == MXML_INTEGER ? "integer" : "real", buffer,
1531 parent ? parent->value.element.name : "null");
1532 break;
1533 }
1534
1535 bufptr = buffer;
1536 whitespace = mxml_isspace(ch) && type == MXML_TEXT;
1537
1538 if (!node && type != MXML_IGNORE)
1539 {
1540 /*
1541 * Print error and return...
1542 */
1543
1544 mxml_error("Unable to add value node of type %s to parent <%s>!",
1545 types[type], parent ? parent->value.element.name : "null");
1546 goto error;
1547 }
1548
1549 if (sax_cb)
1550 {
1551 (*sax_cb)(node, MXML_SAX_DATA, sax_data);
1552
1553 if (!mxmlRelease(node))
1554 node = NULL;
1555 }
1556
1557 if (!first && node)
1558 first = node;
1559 }
1560 else if (mxml_isspace(ch) && type == MXML_TEXT)
1561 whitespace = 1;
1562
1563 /*
1564 * Add lone whitespace node if we have an element and existing
1565 * whitespace...
1566 */
1567
1568 if (ch == '<' && whitespace && type == MXML_TEXT)
1569 {
1570 if (parent)
1571 {
1572 node = mxmlNewText(parent, whitespace, "");
1573
1574 if (sax_cb)
1575 {
1576 (*sax_cb)(node, MXML_SAX_DATA, sax_data);
1577
1578 if (!mxmlRelease(node))
1579 node = NULL;
1580 }
1581
1582 if (!first && node)
1583 first = node;
1584 }
1585
1586 whitespace = 0;
1587 }
1588
1589 if (ch == '<')
1590 {
1591 /*
1592 * Start of open/close tag...
1593 */
1594
1595 bufptr = buffer;
1596
1597 while ((ch = (*getc_cb)(p, &encoding)) != EOF)
1598 if (mxml_isspace(ch) || ch == '>' || (ch == '/' && bufptr > buffer))
1599 break;
1600 else if (ch == '<')
1601 {
1602 mxml_error("Bare < in element!");
1603 goto error;
1604 }
1605 else if (ch == '&')
1606 {
1607 if ((ch = mxml_get_entity(parent, p, &encoding, getc_cb)) == EOF)
1608 goto error;
1609
1610 if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
1611 goto error;
1612 }
1613 else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
1614 goto error;
1615 else if (((bufptr - buffer) == 1 && buffer[0] == '?') ||
1616 ((bufptr - buffer) == 3 && !strncmp(buffer, "!--", 3)) ||
1617 ((bufptr - buffer) == 8 && !strncmp(buffer, "![CDATA[", 8)))
1618 break;
1619
1620 *bufptr = '\0';
1621
1622 if (!strcmp(buffer, "!--"))
1623 {
1624 /*
1625 * Gather rest of comment...
1626 */
1627
1628 while ((ch = (*getc_cb)(p, &encoding)) != EOF)
1629 {
1630 if (ch == '>' && bufptr > (buffer + 4) &&
1631 bufptr[-3] != '-' && bufptr[-2] == '-' && bufptr[-1] == '-')
1632 break;
1633 else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
1634 goto error;
1635 }
1636
1637 /*
1638 * Error out if we didn't get the whole comment...
1639 */
1640
1641 if (ch != '>')
1642 {
1643 /*
1644 * Print error and return...
1645 */
1646
1647 mxml_error("Early EOF in comment node!");
1648 goto error;
1649 }
1650
1651
1652 /*
1653 * Otherwise add this as an element under the current parent...
1654 */
1655
1656 *bufptr = '\0';
1657
1658 if (!parent && first)
1659 {
1660 /*
1661 * There can only be one root element!
1662 */
1663
1664 mxml_error("<%s> cannot be a second root node after <%s>",
1665 buffer, first->value.element.name);
1666 goto error;
1667 }
1668
1669 if ((node = mxmlNewElement(parent, buffer)) == NULL)
1670 {
1671 /*
1672 * Just print error for now...
1673 */
1674
1675 mxml_error("Unable to add comment node to parent <%s>!",
1676 parent ? parent->value.element.name : "null");
1677 break;
1678 }
1679
1680 if (sax_cb)
1681 {
1682 (*sax_cb)(node, MXML_SAX_COMMENT, sax_data);
1683
1684 if (!mxmlRelease(node))
1685 node = NULL;
1686 }
1687
1688 if (node && !first)
1689 first = node;
1690 }
1691 else if (!strcmp(buffer, "![CDATA["))
1692 {
1693 /*
1694 * Gather CDATA section...
1695 */
1696
1697 while ((ch = (*getc_cb)(p, &encoding)) != EOF)
1698 {
1699 if (ch == '>' && !strncmp(bufptr - 2, "]]", 2))
1700 break;
1701 else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
1702 goto error;
1703 }
1704
1705 /*
1706 * Error out if we didn't get the whole comment...
1707 */
1708
1709 if (ch != '>')
1710 {
1711 /*
1712 * Print error and return...
1713 */
1714
1715 mxml_error("Early EOF in CDATA node!");
1716 goto error;
1717 }
1718
1719
1720 /*
1721 * Otherwise add this as an element under the current parent...
1722 */
1723
1724 *bufptr = '\0';
1725
1726 if (!parent && first)
1727 {
1728 /*
1729 * There can only be one root element!
1730 */
1731
1732 mxml_error("<%s> cannot be a second root node after <%s>",
1733 buffer, first->value.element.name);
1734 goto error;
1735 }
1736
1737 if ((node = mxmlNewElement(parent, buffer)) == NULL)
1738 {
1739 /*
1740 * Print error and return...
1741 */
1742
1743 mxml_error("Unable to add CDATA node to parent <%s>!",
1744 parent ? parent->value.element.name : "null");
1745 goto error;
1746 }
1747
1748 if (sax_cb)
1749 {
1750 (*sax_cb)(node, MXML_SAX_CDATA, sax_data);
1751
1752 if (!mxmlRelease(node))
1753 node = NULL;
1754 }
1755
1756 if (node && !first)
1757 first = node;
1758 }
1759 else if (buffer[0] == '?')
1760 {
1761 /*
1762 * Gather rest of processing instruction...
1763 */
1764
1765 while ((ch = (*getc_cb)(p, &encoding)) != EOF)
1766 {
1767 if (ch == '>' && bufptr > buffer && bufptr[-1] == '?')
1768 break;
1769 else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
1770 goto error;
1771 }
1772
1773 /*
1774 * Error out if we didn't get the whole processing instruction...
1775 */
1776
1777 if (ch != '>')
1778 {
1779 /*
1780 * Print error and return...
1781 */
1782
1783 mxml_error("Early EOF in processing instruction node!");
1784 goto error;
1785 }
1786
1787 /*
1788 * Otherwise add this as an element under the current parent...
1789 */
1790
1791 *bufptr = '\0';
1792
1793 if (!parent && first)
1794 {
1795 /*
1796 * There can only be one root element!
1797 */
1798
1799 mxml_error("<%s> cannot be a second root node after <%s>",
1800 buffer, first->value.element.name);
1801 goto error;
1802 }
1803
1804 if ((node = mxmlNewElement(parent, buffer)) == NULL)
1805 {
1806 /*
1807 * Print error and return...
1808 */
1809
1810 mxml_error("Unable to add processing instruction node to parent <%s>!",
1811 parent ? parent->value.element.name : "null");
1812 goto error;
1813 }
1814
1815 if (sax_cb)
1816 {
1817 (*sax_cb)(node, MXML_SAX_DIRECTIVE, sax_data);
1818
1819 if (!mxmlRelease(node))
1820 node = NULL;
1821 }
1822
1823 if (node)
1824 {
1825 if (!first)
1826 first = node;
1827
1828 if (!parent)
1829 {
1830 parent = node;
1831
1832 if (cb)
1833 type = (*cb)(parent);
1834 }
1835 }
1836 }
1837 else if (buffer[0] == '!')
1838 {
1839 /*
1840 * Gather rest of declaration...
1841 */
1842
1843 do
1844 {
1845 if (ch == '>')
1846 break;
1847 else
1848 {
1849 if (ch == '&')
1850 if ((ch = mxml_get_entity(parent, p, &encoding, getc_cb)) == EOF)
1851 goto error;
1852
1853 if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
1854 goto error;
1855 }
1856 }
1857 while ((ch = (*getc_cb)(p, &encoding)) != EOF);
1858
1859 /*
1860 * Error out if we didn't get the whole declaration...
1861 */
1862
1863 if (ch != '>')
1864 {
1865 /*
1866 * Print error and return...
1867 */
1868
1869 mxml_error("Early EOF in declaration node!");
1870 goto error;
1871 }
1872
1873 /*
1874 * Otherwise add this as an element under the current parent...
1875 */
1876
1877 *bufptr = '\0';
1878
1879 if (!parent && first)
1880 {
1881 /*
1882 * There can only be one root element!
1883 */
1884
1885 mxml_error("<%s> cannot be a second root node after <%s>",
1886 buffer, first->value.element.name);
1887 goto error;
1888 }
1889
1890 if ((node = mxmlNewElement(parent, buffer)) == NULL)
1891 {
1892 /*
1893 * Print error and return...
1894 */
1895
1896 mxml_error("Unable to add declaration node to parent <%s>!",
1897 parent ? parent->value.element.name : "null");
1898 goto error;
1899 }
1900
1901 if (sax_cb)
1902 {
1903 (*sax_cb)(node, MXML_SAX_DIRECTIVE, sax_data);
1904
1905 if (!mxmlRelease(node))
1906 node = NULL;
1907 }
1908
1909 if (node)
1910 {
1911 if (!first)
1912 first = node;
1913
1914 if (!parent)
1915 {
1916 parent = node;
1917
1918 if (cb)
1919 type = (*cb)(parent);
1920 }
1921 }
1922 }
1923 else if (buffer[0] == '/')
1924 {
1925 /*
1926 * Handle close tag...
1927 */
1928
1929 if (!parent || strcmp(buffer + 1, parent->value.element.name))
1930 {
1931 /*
1932 * Close tag doesn't match tree; print an error for now...
1933 */
1934
1935 mxml_error("Mismatched close tag <%s> under parent <%s>!",
1936 buffer, parent ? parent->value.element.name : "(null)");
1937 goto error;
1938 }
1939
1940 /*
1941 * Keep reading until we see >...
1942 */
1943
1944 while (ch != '>' && ch != EOF)
1945 ch = (*getc_cb)(p, &encoding);
1946
1947 node = parent;
1948 parent = parent->parent;
1949
1950 if (sax_cb)
1951 {
1952 (*sax_cb)(node, MXML_SAX_ELEMENT_CLOSE, sax_data);
1953
1954 if (!mxmlRelease(node) && first == node)
1955 first = NULL;
1956 }
1957
1958 /*
1959 * Ascend into the parent and set the value type as needed...
1960 */
1961
1962 if (cb && parent)
1963 type = (*cb)(parent);
1964 }
1965 else
1966 {
1967 /*
1968 * Handle open tag...
1969 */
1970
1971 if (!parent && first)
1972 {
1973 /*
1974 * There can only be one root element!
1975 */
1976
1977 mxml_error("<%s> cannot be a second root node after <%s>",
1978 buffer, first->value.element.name);
1979 goto error;
1980 }
1981
1982 if ((node = mxmlNewElement(parent, buffer)) == NULL)
1983 {
1984 /*
1985 * Just print error for now...
1986 */
1987
1988 mxml_error("Unable to add element node to parent <%s>!",
1989 parent ? parent->value.element.name : "null");
1990 goto error;
1991 }
1992
1993 if (mxml_isspace(ch))
1994 {
1995 if ((ch = mxml_parse_element(node, p, &encoding, getc_cb)) == EOF)
1996 goto error;
1997 }
1998 else if (ch == '/')
1999 {
2000 if ((ch = (*getc_cb)(p, &encoding)) != '>')
2001 {
2002 mxml_error("Expected > but got '%c' instead for element <%s/>!",
2003 ch, buffer);
2004 mxmlDelete(node);
2005 goto error;
2006 }
2007
2008 ch = '/';
2009 }
2010
2011 if (sax_cb)
2012 (*sax_cb)(node, MXML_SAX_ELEMENT_OPEN, sax_data);
2013
2014 if (!first)
2015 first = node;
2016
2017 if (ch == EOF)
2018 break;
2019
2020 if (ch != '/')
2021 {
2022 /*
2023 * Descend into this node, setting the value type as needed...
2024 */
2025
2026 parent = node;
2027
2028 if (cb && parent)
2029 type = (*cb)(parent);
2030 }
2031 else if (sax_cb)
2032 {
2033 (*sax_cb)(node, MXML_SAX_ELEMENT_CLOSE, sax_data);
2034
2035 if (!mxmlRelease(node) && first == node)
2036 first = NULL;
2037 }
2038 }
2039
2040 bufptr = buffer;
2041 }
2042 else if (ch == '&')
2043 {
2044 /*
2045 * Add character entity to current buffer...
2046 */
2047
2048 if ((ch = mxml_get_entity(parent, p, &encoding, getc_cb)) == EOF)
2049 goto error;
2050
2051 if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
2052 goto error;
2053 }
2054 else if (type == MXML_OPAQUE || type == MXML_CUSTOM || !mxml_isspace(ch))
2055 {
2056 /*
2057 * Add character to current buffer...
2058 */
2059
2060 if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
2061 goto error;
2062 }
2063 }
2064
2065 /*
2066 * Free the string buffer - we don't need it anymore...
2067 */
2068
2069 free(buffer);
2070
2071 /*
2072 * Find the top element and return it...
2073 */
2074
2075 if (parent)
2076 {
2077 node = parent;
2078
2079 while (parent->parent != top && parent->parent)
2080 parent = parent->parent;
2081
2082 if (node != parent)
2083 {
2084 mxml_error("Missing close tag </%s> under parent <%s>!",
2085 node->value.element.name,
2086 node->parent ? node->parent->value.element.name : "(null)");
2087
2088 mxmlDelete(first);
2089
2090 return (NULL);
2091 }
2092 }
2093
2094 if (parent)
2095 return (parent);
2096 else
2097 return (first);
2098
2099 /*
2100 * Common error return...
2101 */
2102
2103error:
2104
2105 mxmlDelete(first);
2106
2107 free(buffer);
2108
2109 return (NULL);
2110}
2111
2112
2113/*
2114 * 'mxml_parse_element()' - Parse an element for any attributes...
2115 */
2116
2117static int /* O - Terminating character */
2118mxml_parse_element(
2119 mxml_node_t *node, /* I - Element node */
2120 void *p, /* I - Data to read from */
2121 int *encoding, /* IO - Encoding */
2122 _mxml_getc_cb_t getc_cb) /* I - Data callback */
2123{
2124 int ch, /* Current character in file */
2125 quote; /* Quoting character */
2126 char *name, /* Attribute name */
2127 *value, /* Attribute value */
2128 *ptr; /* Pointer into name/value */
2129 int namesize, /* Size of name string */
2130 valsize; /* Size of value string */
2131
2132
2133 /*
2134 * Initialize the name and value buffers...
2135 */
2136
2137 if ((name = malloc(64)) == NULL)
2138 {
2139 mxml_error("Unable to allocate memory for name!");
2140 return (EOF);
2141 }
2142
2143 namesize = 64;
2144
2145 if ((value = malloc(64)) == NULL)
2146 {
2147 free(name);
2148 mxml_error("Unable to allocate memory for value!");
2149 return (EOF);
2150 }
2151
2152 valsize = 64;
2153
2154 /*
2155 * Loop until we hit a >, /, ?, or EOF...
2156 */
2157
2158 while ((ch = (*getc_cb)(p, encoding)) != EOF)
2159 {
2160#if DEBUG > 1
2161 fprintf(stderr, "parse_element: ch='%c'\n", ch);
2162#endif /* DEBUG > 1 */
2163
2164 /*
2165 * Skip leading whitespace...
2166 */
2167
2168 if (mxml_isspace(ch))
2169 continue;
2170
2171 /*
2172 * Stop at /, ?, or >...
2173 */
2174
2175 if (ch == '/' || ch == '?')
2176 {
2177 /*
2178 * Grab the > character and print an error if it isn't there...
2179 */
2180
2181 quote = (*getc_cb)(p, encoding);
2182
2183 if (quote != '>')
2184 {
2185 mxml_error("Expected '>' after '%c' for element %s, but got '%c'!",
2186 ch, node->value.element.name, quote);
2187 goto error;
2188 }
2189
2190 break;
2191 }
2192 else if (ch == '<')
2193 {
2194 mxml_error("Bare < in element %s!", node->value.element.name);
2195 goto error;
2196 }
2197 else if (ch == '>')
2198 break;
2199
2200 /*
2201 * Read the attribute name...
2202 */
2203
2204 name[0] = ch;
2205 ptr = name + 1;
2206
2207 if (ch == '\"' || ch == '\'')
2208 {
2209 /*
2210 * Name is in quotes, so get a quoted string...
2211 */
2212
2213 quote = ch;
2214
2215 while ((ch = (*getc_cb)(p, encoding)) != EOF)
2216 {
2217 if (ch == '&')
2218 if ((ch = mxml_get_entity(node, p, encoding, getc_cb)) == EOF)
2219 goto error;
2220
2221 if (mxml_add_char(ch, &ptr, &name, &namesize))
2222 goto error;
2223
2224 if (ch == quote)
2225 break;
2226 }
2227 }
2228 else
2229 {
2230 /*
2231 * Grab an normal, non-quoted name...
2232 */
2233
2234 while ((ch = (*getc_cb)(p, encoding)) != EOF)
2235 if (mxml_isspace(ch) || ch == '=' || ch == '/' || ch == '>' ||
2236 ch == '?')
2237 break;
2238 else
2239 {
2240 if (ch == '&')
2241 if ((ch = mxml_get_entity(node, p, encoding, getc_cb)) == EOF)
2242 goto error;
2243
2244 if (mxml_add_char(ch, &ptr, &name, &namesize))
2245 goto error;
2246 }
2247 }
2248
2249 *ptr = '\0';
2250
2251 if (mxmlElementGetAttr(node, name))
2252 goto error;
2253
2254 while (ch != EOF && mxml_isspace(ch))
2255 ch = (*getc_cb)(p, encoding);
2256
2257 if (ch == '=')
2258 {
2259 /*
2260 * Read the attribute value...
2261 */
2262
2263 while ((ch = (*getc_cb)(p, encoding)) != EOF && mxml_isspace(ch));
2264
2265 if (ch == EOF)
2266 {
2267 mxml_error("Missing value for attribute '%s' in element %s!",
2268 name, node->value.element.name);
2269 goto error;
2270 }
2271
2272 if (ch == '\'' || ch == '\"')
2273 {
2274 /*
2275 * Read quoted value...
2276 */
2277
2278 quote = ch;
2279 ptr = value;
2280
2281 while ((ch = (*getc_cb)(p, encoding)) != EOF)
2282 if (ch == quote)
2283 break;
2284 else
2285 {
2286 if (ch == '&')
2287 if ((ch = mxml_get_entity(node, p, encoding, getc_cb)) == EOF)
2288 goto error;
2289
2290 if (mxml_add_char(ch, &ptr, &value, &valsize))
2291 goto error;
2292 }
2293
2294 *ptr = '\0';
2295 }
2296 else
2297 {
2298 /*
2299 * Read unquoted value...
2300 */
2301
2302 value[0] = ch;
2303 ptr = value + 1;
2304
2305 while ((ch = (*getc_cb)(p, encoding)) != EOF)
2306 if (mxml_isspace(ch) || ch == '=' || ch == '/' || ch == '>')
2307 break;
2308 else
2309 {
2310 if (ch == '&')
2311 if ((ch = mxml_get_entity(node, p, encoding, getc_cb)) == EOF)
2312 goto error;
2313
2314 if (mxml_add_char(ch, &ptr, &value, &valsize))
2315 goto error;
2316 }
2317
2318 *ptr = '\0';
2319 }
2320
2321 /*
2322 * Set the attribute with the given string value...
2323 */
2324
2325 mxmlElementSetAttr(node, name, value);
2326 }
2327 else
2328 {
2329 mxml_error("Missing value for attribute '%s' in element %s!",
2330 name, node->value.element.name);
2331 goto error;
2332 }
2333
2334 /*
2335 * Check the end character...
2336 */
2337
2338 if (ch == '/' || ch == '?')
2339 {
2340 /*
2341 * Grab the > character and print an error if it isn't there...
2342 */
2343
2344 quote = (*getc_cb)(p, encoding);
2345
2346 if (quote != '>')
2347 {
2348 mxml_error("Expected '>' after '%c' for element %s, but got '%c'!",
2349 ch, node->value.element.name, quote);
2350 ch = EOF;
2351 }
2352
2353 break;
2354 }
2355 else if (ch == '>')
2356 break;
2357 }
2358
2359 /*
2360 * Free the name and value buffers and return...
2361 */
2362
2363 free(name);
2364 free(value);
2365
2366 return (ch);
2367
2368 /*
2369 * Common error return point...
2370 */
2371
2372error:
2373
2374 free(name);
2375 free(value);
2376
2377 return (EOF);
2378}
2379
2380
2381/*
2382 * 'mxml_string_getc()' - Get a character from a string.
2383 */
2384
2385static int /* O - Character or EOF */
2386mxml_string_getc(void *p, /* I - Pointer to file */
2387 int *encoding) /* IO - Encoding */
2388{
2389 int ch; /* Character */
2390 const char **s; /* Pointer to string pointer */
2391
2392
2393 s = (const char **)p;
2394
2395 if ((ch = (*s)[0] & 255) != 0 || *encoding == ENCODE_UTF16LE)
2396 {
2397 /*
2398 * Got character; convert UTF-8 to integer and return...
2399 */
2400
2401 (*s)++;
2402
2403 switch (*encoding)
2404 {
2405 case ENCODE_UTF8 :
2406 if (!(ch & 0x80))
2407 {
2408#if DEBUG > 1
2409 printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
2410#endif /* DEBUG > 1 */
2411
2412 if (mxml_bad_char(ch))
2413 {
2414 mxml_error("Bad control character 0x%02x not allowed by XML standard!",
2415 ch);
2416 return (EOF);
2417 }
2418
2419 return (ch);
2420 }
2421 else if (ch == 0xfe)
2422 {
2423 /*
2424 * UTF-16 big-endian BOM?
2425 */
2426
2427 if (((*s)[0] & 255) != 0xff)
2428 return (EOF);
2429
2430 *encoding = ENCODE_UTF16BE;
2431 (*s)++;
2432
2433 return (mxml_string_getc(p, encoding));
2434 }
2435 else if (ch == 0xff)
2436 {
2437 /*
2438 * UTF-16 little-endian BOM?
2439 */
2440
2441 if (((*s)[0] & 255) != 0xfe)
2442 return (EOF);
2443
2444 *encoding = ENCODE_UTF16LE;
2445 (*s)++;
2446
2447 return (mxml_string_getc(p, encoding));
2448 }
2449 else if ((ch & 0xe0) == 0xc0)
2450 {
2451 /*
2452 * Two-byte value...
2453 */
2454
2455 if (((*s)[0] & 0xc0) != 0x80)
2456 return (EOF);
2457
2458 ch = ((ch & 0x1f) << 6) | ((*s)[0] & 0x3f);
2459
2460 (*s)++;
2461
2462 if (ch < 0x80)
2463 {
2464 mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
2465 return (EOF);
2466 }
2467
2468#if DEBUG > 1
2469 printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
2470#endif /* DEBUG > 1 */
2471
2472 return (ch);
2473 }
2474 else if ((ch & 0xf0) == 0xe0)
2475 {
2476 /*
2477 * Three-byte value...
2478 */
2479
2480 if (((*s)[0] & 0xc0) != 0x80 ||
2481 ((*s)[1] & 0xc0) != 0x80)
2482 return (EOF);
2483
2484 ch = ((((ch & 0x0f) << 6) | ((*s)[0] & 0x3f)) << 6) | ((*s)[1] & 0x3f);
2485
2486 (*s) += 2;
2487
2488 if (ch < 0x800)
2489 {
2490 mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
2491 return (EOF);
2492 }
2493
2494 /*
2495 * Ignore (strip) Byte Order Mark (BOM)...
2496 */
2497
2498 if (ch == 0xfeff)
2499 return (mxml_string_getc(p, encoding));
2500
2501#if DEBUG > 1
2502 printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
2503#endif /* DEBUG > 1 */
2504
2505 return (ch);
2506 }
2507 else if ((ch & 0xf8) == 0xf0)
2508 {
2509 /*
2510 * Four-byte value...
2511 */
2512
2513 if (((*s)[0] & 0xc0) != 0x80 ||
2514 ((*s)[1] & 0xc0) != 0x80 ||
2515 ((*s)[2] & 0xc0) != 0x80)
2516 return (EOF);
2517
2518 ch = ((((((ch & 0x07) << 6) | ((*s)[0] & 0x3f)) << 6) |
2519 ((*s)[1] & 0x3f)) << 6) | ((*s)[2] & 0x3f);
2520
2521 (*s) += 3;
2522
2523 if (ch < 0x10000)
2524 {
2525 mxml_error("Invalid UTF-8 sequence for character 0x%04x!", ch);
2526 return (EOF);
2527 }
2528
2529#if DEBUG > 1
2530 printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
2531#endif /* DEBUG > 1 */
2532
2533 return (ch);
2534 }
2535 else
2536 return (EOF);
2537
2538 case ENCODE_UTF16BE :
2539 /*
2540 * Read UTF-16 big-endian char...
2541 */
2542
2543 ch = (ch << 8) | ((*s)[0] & 255);
2544 (*s) ++;
2545
2546 if (mxml_bad_char(ch))
2547 {
2548 mxml_error("Bad control character 0x%02x not allowed by XML standard!",
2549 ch);
2550 return (EOF);
2551 }
2552 else if (ch >= 0xd800 && ch <= 0xdbff)
2553 {
2554 /*
2555 * Multi-word UTF-16 char...
2556 */
2557
2558 int lch; /* Lower word */
2559
2560
2561 if (!(*s)[0])
2562 return (EOF);
2563
2564 lch = (((*s)[0] & 255) << 8) | ((*s)[1] & 255);
2565 (*s) += 2;
2566
2567 if (lch < 0xdc00 || lch >= 0xdfff)
2568 return (EOF);
2569
2570 ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
2571 }
2572
2573#if DEBUG > 1
2574 printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
2575#endif /* DEBUG > 1 */
2576
2577 return (ch);
2578
2579 case ENCODE_UTF16LE :
2580 /*
2581 * Read UTF-16 little-endian char...
2582 */
2583
2584 ch = ch | (((*s)[0] & 255) << 8);
2585
2586 if (!ch)
2587 {
2588 (*s) --;
2589 return (EOF);
2590 }
2591
2592 (*s) ++;
2593
2594 if (mxml_bad_char(ch))
2595 {
2596 mxml_error("Bad control character 0x%02x not allowed by XML standard!",
2597 ch);
2598 return (EOF);
2599 }
2600 else if (ch >= 0xd800 && ch <= 0xdbff)
2601 {
2602 /*
2603 * Multi-word UTF-16 char...
2604 */
2605
2606 int lch; /* Lower word */
2607
2608
2609 if (!(*s)[1])
2610 return (EOF);
2611
2612 lch = (((*s)[1] & 255) << 8) | ((*s)[0] & 255);
2613 (*s) += 2;
2614
2615 if (lch < 0xdc00 || lch >= 0xdfff)
2616 return (EOF);
2617
2618 ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
2619 }
2620
2621#if DEBUG > 1
2622 printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
2623#endif /* DEBUG > 1 */
2624
2625 return (ch);
2626 }
2627 }
2628
2629 return (EOF);
2630}
2631
2632
2633/*
2634 * 'mxml_string_putc()' - Write a character to a string.
2635 */
2636
2637static int /* O - 0 on success, -1 on failure */
2638mxml_string_putc(int ch, /* I - Character to write */
2639 void *p) /* I - Pointer to string pointers */
2640{
2641 char **pp; /* Pointer to string pointers */
2642
2643
2644 pp = (char **)p;
2645
2646 if (pp[0] < pp[1])
2647 pp[0][0] = ch;
2648
2649 pp[0] ++;
2650
2651 return (0);
2652}
2653
2654
2655/*
2656 * 'mxml_write_name()' - Write a name string.
2657 */
2658
2659static int /* O - 0 on success, -1 on failure */
2660mxml_write_name(const char *s, /* I - Name to write */
2661 void *p, /* I - Write pointer */
2662 int (*putc_cb)(int, void *))
2663 /* I - Write callback */
2664{
2665 char quote; /* Quote character */
2666 const char *name; /* Entity name */
2667
2668
2669 if (*s == '\"' || *s == '\'')
2670 {
2671 /*
2672 * Write a quoted name string...
2673 */
2674
2675 if ((*putc_cb)(*s, p) < 0)
2676 return (-1);
2677
2678 quote = *s++;
2679
2680 while (*s && *s != quote)
2681 {
2682 if ((name = mxmlEntityGetName(*s)) != NULL)
2683 {
2684 if ((*putc_cb)('&', p) < 0)
2685 return (-1);
2686
2687 while (*name)
2688 {
2689 if ((*putc_cb)(*name, p) < 0)
2690 return (-1);
2691
2692 name ++;
2693 }
2694
2695 if ((*putc_cb)(';', p) < 0)
2696 return (-1);
2697 }
2698 else if ((*putc_cb)(*s, p) < 0)
2699 return (-1);
2700
2701 s ++;
2702 }
2703
2704 /*
2705 * Write the end quote...
2706 */
2707
2708 if ((*putc_cb)(quote, p) < 0)
2709 return (-1);
2710 }
2711 else
2712 {
2713 /*
2714 * Write a non-quoted name string...
2715 */
2716
2717 while (*s)
2718 {
2719 if ((*putc_cb)(*s, p) < 0)
2720 return (-1);
2721
2722 s ++;
2723 }
2724 }
2725
2726 return (0);
2727}
2728
2729
2730/*
2731 * 'mxml_write_node()' - Save an XML node to a file.
2732 */
2733
2734static int /* O - Column or -1 on error */
2735mxml_write_node(mxml_node_t *node, /* I - Node to write */
2736 void *p, /* I - File to write to */
2737 mxml_save_cb_t cb, /* I - Whitespace callback */
2738 int col, /* I - Current column */
2739 _mxml_putc_cb_t putc_cb,/* I - Output callback */
2740 _mxml_global_t *global)/* I - Global data */
2741{
2742 int i, /* Looping var */
2743 width; /* Width of attr + value */
2744 mxml_attr_t *attr; /* Current attribute */
2745 char s[255]; /* Temporary string */
2746
2747
2748 /*
2749 * Print the node value...
2750 */
2751
2752 switch (node->type)
2753 {
2754 case MXML_ELEMENT :
2755 col = mxml_write_ws(node, p, cb, MXML_WS_BEFORE_OPEN, col, putc_cb);
2756
2757 if ((*putc_cb)('<', p) < 0)
2758 return (-1);
2759 if (node->value.element.name[0] == '?' ||
2760 !strncmp(node->value.element.name, "!--", 3) ||
2761 !strncmp(node->value.element.name, "![CDATA[", 8))
2762 {
2763 /*
2764 * Comments, CDATA, and processing instructions do not
2765 * use character entities.
2766 */
2767
2768 const char *ptr; /* Pointer into name */
2769
2770
2771 for (ptr = node->value.element.name; *ptr; ptr ++)
2772 if ((*putc_cb)(*ptr, p) < 0)
2773 return (-1);
2774 }
2775 else if (mxml_write_name(node->value.element.name, p, putc_cb) < 0)
2776 return (-1);
2777
2778 col += strlen(node->value.element.name) + 1;
2779
2780 for (i = node->value.element.num_attrs, attr = node->value.element.attrs;
2781 i > 0;
2782 i --, attr ++)
2783 {
2784 width = strlen(attr->name);
2785
2786 if (attr->value)
2787 width += strlen(attr->value) + 3;
2788
2789 if (global->wrap > 0 && (col + width) > global->wrap)
2790 {
2791 if ((*putc_cb)('\n', p) < 0)
2792 return (-1);
2793
2794 col = 0;
2795 }
2796 else
2797 {
2798 if ((*putc_cb)(' ', p) < 0)
2799 return (-1);
2800
2801 col ++;
2802 }
2803
2804 if (mxml_write_name(attr->name, p, putc_cb) < 0)
2805 return (-1);
2806
2807 if (attr->value)
2808 {
2809 if ((*putc_cb)('=', p) < 0)
2810 return (-1);
2811 if ((*putc_cb)('\"', p) < 0)
2812 return (-1);
2813 if (mxml_write_string(attr->value, p, putc_cb) < 0)
2814 return (-1);
2815 if ((*putc_cb)('\"', p) < 0)
2816 return (-1);
2817 }
2818
2819 col += width;
2820 }
2821
2822 if (node->child)
2823 {
2824 /*
2825 * Write children...
2826 */
2827
2828 mxml_node_t *child; /* Current child */
2829
2830
2831 if ((*putc_cb)('>', p) < 0)
2832 return (-1);
2833 else
2834 col ++;
2835
2836 col = mxml_write_ws(node, p, cb, MXML_WS_AFTER_OPEN, col, putc_cb);
2837
2838 for (child = node->child; child; child = child->next)
2839 {
2840 if ((col = mxml_write_node(child, p, cb, col, putc_cb, global)) < 0)
2841 return (-1);
2842 }
2843
2844 /*
2845 * The ? and ! elements are special-cases and have no end tags...
2846 */
2847
2848 if (node->value.element.name[0] != '!' &&
2849 node->value.element.name[0] != '?')
2850 {
2851 col = mxml_write_ws(node, p, cb, MXML_WS_BEFORE_CLOSE, col, putc_cb);
2852
2853 if ((*putc_cb)('<', p) < 0)
2854 return (-1);
2855 if ((*putc_cb)('/', p) < 0)
2856 return (-1);
2857 if (mxml_write_string(node->value.element.name, p, putc_cb) < 0)
2858 return (-1);
2859 if ((*putc_cb)('>', p) < 0)
2860 return (-1);
2861
2862 col += strlen(node->value.element.name) + 3;
2863
2864 col = mxml_write_ws(node, p, cb, MXML_WS_AFTER_CLOSE, col, putc_cb);
2865 }
2866 }
2867 else if (node->value.element.name[0] == '!' ||
2868 node->value.element.name[0] == '?')
2869 {
2870 /*
2871 * The ? and ! elements are special-cases...
2872 */
2873
2874 if ((*putc_cb)('>', p) < 0)
2875 return (-1);
2876 else
2877 col ++;
2878
2879 col = mxml_write_ws(node, p, cb, MXML_WS_AFTER_OPEN, col, putc_cb);
2880 }
2881 else
2882 {
2883 if ((*putc_cb)(' ', p) < 0)
2884 return (-1);
2885 if ((*putc_cb)('/', p) < 0)
2886 return (-1);
2887 if ((*putc_cb)('>', p) < 0)
2888 return (-1);
2889
2890 col += 3;
2891
2892 col = mxml_write_ws(node, p, cb, MXML_WS_AFTER_OPEN, col, putc_cb);
2893 }
2894 break;
2895
2896 case MXML_INTEGER :
2897 if (node->prev)
2898 {
2899 if (global->wrap > 0 && col > global->wrap)
2900 {
2901 if ((*putc_cb)('\n', p) < 0)
2902 return (-1);
2903
2904 col = 0;
2905 }
2906 else if ((*putc_cb)(' ', p) < 0)
2907 return (-1);
2908 else
2909 col ++;
2910 }
2911
2912 sprintf(s, "%d", node->value.integer);
2913 if (mxml_write_string(s, p, putc_cb) < 0)
2914 return (-1);
2915
2916 col += strlen(s);
2917 break;
2918
2919 case MXML_OPAQUE :
2920 if (mxml_write_string(node->value.opaque, p, putc_cb) < 0)
2921 return (-1);
2922
2923 col += strlen(node->value.opaque);
2924 break;
2925
2926 case MXML_REAL :
2927 if (node->prev)
2928 {
2929 if (global->wrap > 0 && col > global->wrap)
2930 {
2931 if ((*putc_cb)('\n', p) < 0)
2932 return (-1);
2933
2934 col = 0;
2935 }
2936 else if ((*putc_cb)(' ', p) < 0)
2937 return (-1);
2938 else
2939 col ++;
2940 }
2941
2942 sprintf(s, "%f", node->value.real);
2943 if (mxml_write_string(s, p, putc_cb) < 0)
2944 return (-1);
2945
2946 col += strlen(s);
2947 break;
2948
2949 case MXML_TEXT :
2950 if (node->value.text.whitespace && col > 0)
2951 {
2952 if (global->wrap > 0 && col > global->wrap)
2953 {
2954 if ((*putc_cb)('\n', p) < 0)
2955 return (-1);
2956
2957 col = 0;
2958 }
2959 else if ((*putc_cb)(' ', p) < 0)
2960 return (-1);
2961 else
2962 col ++;
2963 }
2964
2965 if (mxml_write_string(node->value.text.string, p, putc_cb) < 0)
2966 return (-1);
2967
2968 col += strlen(node->value.text.string);
2969 break;
2970
2971 case MXML_CUSTOM :
2972 if (global->custom_save_cb)
2973 {
2974 char *data; /* Custom data string */
2975 const char *newline; /* Last newline in string */
2976
2977
2978 if ((data = (*global->custom_save_cb)(node)) == NULL)
2979 return (-1);
2980
2981 if (mxml_write_string(data, p, putc_cb) < 0)
2982 return (-1);
2983
2984 if ((newline = strrchr(data, '\n')) == NULL)
2985 col += strlen(data);
2986 else
2987 col = strlen(newline);
2988
2989 free(data);
2990 break;
2991 }
2992
2993 default : /* Should never happen */
2994 return (-1);
2995 }
2996
2997 return (col);
2998}
2999
3000
3001/*
3002 * 'mxml_write_string()' - Write a string, escaping & and < as needed.
3003 */
3004
3005static int /* O - 0 on success, -1 on failure */
3006mxml_write_string(
3007 const char *s, /* I - String to write */
3008 void *p, /* I - Write pointer */
3009 _mxml_putc_cb_t putc_cb) /* I - Write callback */
3010{
3011 const char *name; /* Entity name, if any */
3012
3013
3014 while (*s)
3015 {
3016 if ((name = mxmlEntityGetName(*s)) != NULL)
3017 {
3018 if ((*putc_cb)('&', p) < 0)
3019 return (-1);
3020
3021 while (*name)
3022 {
3023 if ((*putc_cb)(*name, p) < 0)
3024 return (-1);
3025 name ++;
3026 }
3027
3028 if ((*putc_cb)(';', p) < 0)
3029 return (-1);
3030 }
3031 else if ((*putc_cb)(*s, p) < 0)
3032 return (-1);
3033
3034 s ++;
3035 }
3036
3037 return (0);
3038}
3039
3040
3041/*
3042 * 'mxml_write_ws()' - Do whitespace callback...
3043 */
3044
3045static int /* O - New column */
3046mxml_write_ws(mxml_node_t *node, /* I - Current node */
3047 void *p, /* I - Write pointer */
3048 mxml_save_cb_t cb, /* I - Callback function */
3049 int ws, /* I - Where value */
3050 int col, /* I - Current column */
3051 _mxml_putc_cb_t putc_cb) /* I - Write callback */
3052{
3053 const char *s; /* Whitespace string */
3054
3055
3056 if (cb && (s = (*cb)(node, ws)) != NULL)
3057 {
3058 while (*s)
3059 {
3060 if ((*putc_cb)(*s, p) < 0)
3061 return (-1);
3062 else if (*s == '\n')
3063 col = 0;
3064 else if (*s == '\t')
3065 {
3066 col += MXML_TAB;
3067 col = col - (col % MXML_TAB);
3068 }
3069 else
3070 col ++;
3071
3072 s ++;
3073 }
3074 }
3075
3076 return (col);
3077}
3078
3079
3080/*
3081 * End of "$Id: mxml-file.c 438 2011-03-24 05:47:51Z mike $".
3082 */
diff --git a/tools/gator/daemon/mxml/mxml-get.c b/tools/gator/daemon/mxml/mxml-get.c
new file mode 100644
index 00000000000..a5356d57e18
--- /dev/null
+++ b/tools/gator/daemon/mxml/mxml-get.c
@@ -0,0 +1,471 @@
1/*
2 * "$Id: mxml-get.c 427 2011-01-03 02:03:29Z mike $"
3 *
4 * Node get functions for Mini-XML, a small XML-like file parsing library.
5 *
6 * Copyright 2011 by Michael R Sweet.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Michael R Sweet and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "COPYING"
11 * which should have been included with this file. If this file is
12 * missing or damaged, see the license at:
13 *
14 * http://www.minixml.org/
15 *
16 * Contents:
17 *
18 * mxmlGetCDATA() - Get the value for a CDATA node.
19 * mxmlGetCustom() - Get the value for a custom node.
20 * mxmlGetElement() - Get the name for an element node.
21 * mxmlGetFirstChild() - Get the first child of an element node.
22 * mxmlGetInteger() - Get the integer value from the specified node or its
23 * first child.
24 * mxmlGetLastChild() - Get the last child of an element node.
25 * mxmlGetNextSibling() - Get the next node for the current parent.
26 * mxmlGetOpaque() - Get an opaque string value for a node or its first
27 * child.
28 * mxmlGetParent() - Get the parent node.
29 * mxmlGetPrevSibling() - Get the previous node for the current parent.
30 * mxmlGetReal() - Get the real value for a node or its first child.
31 * mxmlGetText() - Get the text value for a node or its first child.
32 * mxmlGetType() - Get the node type.
33 * mxmlGetUserData() - Get the user data pointer for a node.
34 */
35
36/*
37 * Include necessary headers...
38 */
39
40#include "config.h"
41#include "mxml.h"
42
43
44/*
45 * 'mxmlGetCDATA()' - Get the value for a CDATA node.
46 *
47 * @code NULL@ is returned if the node is not a CDATA element.
48 *
49 * @since Mini-XML 2.7@
50 */
51
52const char * /* O - CDATA value or NULL */
53mxmlGetCDATA(mxml_node_t *node) /* I - Node to get */
54{
55 /*
56 * Range check input...
57 */
58
59 if (!node || node->type != MXML_ELEMENT ||
60 strncmp(node->value.element.name, "![CDATA[", 8))
61 return (NULL);
62
63 /*
64 * Return the text following the CDATA declaration...
65 */
66
67 return (node->value.element.name + 8);
68}
69
70
71/*
72 * 'mxmlGetCustom()' - Get the value for a custom node.
73 *
74 * @code NULL@ is returned if the node (or its first child) is not a custom
75 * value node.
76 *
77 * @since Mini-XML 2.7@
78 */
79
80const void * /* O - Custom value or NULL */
81mxmlGetCustom(mxml_node_t *node) /* I - Node to get */
82{
83 /*
84 * Range check input...
85 */
86
87 if (!node)
88 return (NULL);
89
90 /*
91 * Return the integer value...
92 */
93
94 if (node->type == MXML_CUSTOM)
95 return (node->value.custom.data);
96 else if (node->type == MXML_ELEMENT &&
97 node->child &&
98 node->child->type == MXML_CUSTOM)
99 return (node->child->value.custom.data);
100 else
101 return (NULL);
102}
103
104
105/*
106 * 'mxmlGetElement()' - Get the name for an element node.
107 *
108 * @code NULL@ is returned if the node is not an element node.
109 *
110 * @since Mini-XML 2.7@
111 */
112
113const char * /* O - Element name or NULL */
114mxmlGetElement(mxml_node_t *node) /* I - Node to get */
115{
116 /*
117 * Range check input...
118 */
119
120 if (!node || node->type != MXML_ELEMENT)
121 return (NULL);
122
123 /*
124 * Return the element name...
125 */
126
127 return (node->value.element.name);
128}
129
130
131/*
132 * 'mxmlGetFirstChild()' - Get the first child of an element node.
133 *
134 * @code NULL@ is returned if the node is not an element node or if the node
135 * has no children.
136 *
137 * @since Mini-XML 2.7@
138 */
139
140mxml_node_t * /* O - First child or NULL */
141mxmlGetFirstChild(mxml_node_t *node) /* I - Node to get */
142{
143 /*
144 * Range check input...
145 */
146
147 if (!node || node->type != MXML_ELEMENT)
148 return (NULL);
149
150 /*
151 * Return the first child node...
152 */
153
154 return (node->child);
155}
156
157
158/*
159 * 'mxmlGetInteger()' - Get the integer value from the specified node or its
160 * first child.
161 *
162 * 0 is returned if the node (or its first child) is not an integer value node.
163 *
164 * @since Mini-XML 2.7@
165 */
166
167int /* O - Integer value or 0 */
168mxmlGetInteger(mxml_node_t *node) /* I - Node to get */
169{
170 /*
171 * Range check input...
172 */
173
174 if (!node)
175 return (0);
176
177 /*
178 * Return the integer value...
179 */
180
181 if (node->type == MXML_INTEGER)
182 return (node->value.integer);
183 else if (node->type == MXML_ELEMENT &&
184 node->child &&
185 node->child->type == MXML_INTEGER)
186 return (node->child->value.integer);
187 else
188 return (0);
189}
190
191
192/*
193 * 'mxmlGetLastChild()' - Get the last child of an element node.
194 *
195 * @code NULL@ is returned if the node is not an element node or if the node
196 * has no children.
197 *
198 * @since Mini-XML 2.7@
199 */
200
201mxml_node_t * /* O - Last child or NULL */
202mxmlGetLastChild(mxml_node_t *node) /* I - Node to get */
203{
204 /*
205 * Range check input...
206 */
207
208 if (!node || node->type != MXML_ELEMENT)
209 return (NULL);
210
211 /*
212 * Return the node type...
213 */
214
215 return (node->last_child);
216}
217
218
219/*
220 * 'mxmlGetNextSibling()' - Get the next node for the current parent.
221 *
222 * @code NULL@ is returned if this is the last child for the current parent.
223 *
224 * @since Mini-XML 2.7@
225 */
226
227mxml_node_t *
228mxmlGetNextSibling(mxml_node_t *node) /* I - Node to get */
229{
230 /*
231 * Range check input...
232 */
233
234 if (!node)
235 return (NULL);
236
237 /*
238 * Return the node type...
239 */
240
241 return (node->next);
242}
243
244
245/*
246 * 'mxmlGetOpaque()' - Get an opaque string value for a node or its first child.
247 *
248 * @code NULL@ is returned if the node (or its first child) is not an opaque
249 * value node.
250 *
251 * @since Mini-XML 2.7@
252 */
253
254const char * /* O - Opaque string or NULL */
255mxmlGetOpaque(mxml_node_t *node) /* I - Node to get */
256{
257 /*
258 * Range check input...
259 */
260
261 if (!node)
262 return (NULL);
263
264 /*
265 * Return the integer value...
266 */
267
268 if (node->type == MXML_OPAQUE)
269 return (node->value.opaque);
270 else if (node->type == MXML_ELEMENT &&
271 node->child &&
272 node->child->type == MXML_OPAQUE)
273 return (node->child->value.opaque);
274 else
275 return (NULL);
276}
277
278
279/*
280 * 'mxmlGetParent()' - Get the parent node.
281 *
282 * @code NULL@ is returned for a root node.
283 *
284 * @since Mini-XML 2.7@
285 */
286
287mxml_node_t * /* O - Parent node or NULL */
288mxmlGetParent(mxml_node_t *node) /* I - Node to get */
289{
290 /*
291 * Range check input...
292 */
293
294 if (!node)
295 return (NULL);
296
297 /*
298 * Return the node type...
299 */
300
301 return (node->parent);
302}
303
304
305/*
306 * 'mxmlGetPrevSibling()' - Get the previous node for the current parent.
307 *
308 * @code NULL@ is returned if this is the first child for the current parent.
309 *
310 * @since Mini-XML 2.7@
311 */
312
313mxml_node_t * /* O - Previous node or NULL */
314mxmlGetPrevSibling(mxml_node_t *node) /* I - Node to get */
315{
316 /*
317 * Range check input...
318 */
319
320 if (!node)
321 return (NULL);
322
323 /*
324 * Return the node type...
325 */
326
327 return (node->prev);
328}
329
330
331/*
332 * 'mxmlGetReal()' - Get the real value for a node or its first child.
333 *
334 * 0.0 is returned if the node (or its first child) is not a real value node.
335 *
336 * @since Mini-XML 2.7@
337 */
338
339double /* O - Real value or 0.0 */
340mxmlGetReal(mxml_node_t *node) /* I - Node to get */
341{
342 /*
343 * Range check input...
344 */
345
346 if (!node)
347 return (0.0);
348
349 /*
350 * Return the integer value...
351 */
352
353 if (node->type == MXML_REAL)
354 return (node->value.real);
355 else if (node->type == MXML_ELEMENT &&
356 node->child &&
357 node->child->type == MXML_REAL)
358 return (node->child->value.real);
359 else
360 return (0.0);
361}
362
363
364/*
365 * 'mxmlGetText()' - Get the text value for a node or its first child.
366 *
367 * @code NULL@ is returned if the node (or its first child) is not a text node.
368 * The "whitespace" argument can be NULL.
369 *
370 * @since Mini-XML 2.7@
371 */
372
373const char * /* O - Text string or NULL */
374mxmlGetText(mxml_node_t *node, /* I - Node to get */
375 int *whitespace) /* O - 1 if string is preceded by whitespace, 0 otherwise */
376{
377 /*
378 * Range check input...
379 */
380
381 if (!node)
382 {
383 if (whitespace)
384 *whitespace = 0;
385
386 return (NULL);
387 }
388
389 /*
390 * Return the integer value...
391 */
392
393 if (node->type == MXML_TEXT)
394 {
395 if (whitespace)
396 *whitespace = node->value.text.whitespace;
397
398 return (node->value.text.string);
399 }
400 else if (node->type == MXML_ELEMENT &&
401 node->child &&
402 node->child->type == MXML_TEXT)
403 {
404 if (whitespace)
405 *whitespace = node->child->value.text.whitespace;
406
407 return (node->child->value.text.string);
408 }
409 else
410 {
411 if (whitespace)
412 *whitespace = 0;
413
414 return (NULL);
415 }
416}
417
418
419/*
420 * 'mxmlGetType()' - Get the node type.
421 *
422 * @code MXML_IGNORE@ is returned if "node" is @code NULL@.
423 *
424 * @since Mini-XML 2.7@
425 */
426
427mxml_type_t /* O - Type of node */
428mxmlGetType(mxml_node_t *node) /* I - Node to get */
429{
430 /*
431 * Range check input...
432 */
433
434 if (!node)
435 return (MXML_IGNORE);
436
437 /*
438 * Return the node type...
439 */
440
441 return (node->type);
442}
443
444
445/*
446 * 'mxmlGetUserData()' - Get the user data pointer for a node.
447 *
448 * @since Mini-XML 2.7@
449 */
450
451void * /* O - User data pointer */
452mxmlGetUserData(mxml_node_t *node) /* I - Node to get */
453{
454 /*
455 * Range check input...
456 */
457
458 if (!node)
459 return (NULL);
460
461 /*
462 * Return the user data pointer...
463 */
464
465 return (node->user_data);
466}
467
468
469/*
470 * End of "$Id: mxml-get.c 427 2011-01-03 02:03:29Z mike $".
471 */
diff --git a/tools/gator/daemon/mxml/mxml-index.c b/tools/gator/daemon/mxml/mxml-index.c
new file mode 100644
index 00000000000..b6efc66f055
--- /dev/null
+++ b/tools/gator/daemon/mxml/mxml-index.c
@@ -0,0 +1,662 @@
1/*
2 * "$Id: mxml-index.c 426 2011-01-01 23:42:17Z mike $"
3 *
4 * Index support code for Mini-XML, a small XML-like file parsing library.
5 *
6 * Copyright 2003-2011 by Michael R Sweet.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Michael R Sweet and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "COPYING"
11 * which should have been included with this file. If this file is
12 * missing or damaged, see the license at:
13 *
14 * http://www.minixml.org/
15 *
16 * Contents:
17 *
18 */
19
20/*
21 * Include necessary headers...
22 */
23
24#include "config.h"
25#include "mxml.h"
26
27
28/*
29 * Sort functions...
30 */
31
32static int index_compare(mxml_index_t *ind, mxml_node_t *first,
33 mxml_node_t *second);
34static int index_find(mxml_index_t *ind, const char *element,
35 const char *value, mxml_node_t *node);
36static void index_sort(mxml_index_t *ind, int left, int right);
37
38
39/*
40 * 'mxmlIndexDelete()' - Delete an index.
41 */
42
43void
44mxmlIndexDelete(mxml_index_t *ind) /* I - Index to delete */
45{
46 /*
47 * Range check input..
48 */
49
50 if (!ind)
51 return;
52
53 /*
54 * Free memory...
55 */
56
57 if (ind->attr)
58 free(ind->attr);
59
60 if (ind->alloc_nodes)
61 free(ind->nodes);
62
63 free(ind);
64}
65
66
67/*
68 * 'mxmlIndexEnum()' - Return the next node in the index.
69 *
70 * Nodes are returned in the sorted order of the index.
71 */
72
73mxml_node_t * /* O - Next node or NULL if there is none */
74mxmlIndexEnum(mxml_index_t *ind) /* I - Index to enumerate */
75{
76 /*
77 * Range check input...
78 */
79
80 if (!ind)
81 return (NULL);
82
83 /*
84 * Return the next node...
85 */
86
87 if (ind->cur_node < ind->num_nodes)
88 return (ind->nodes[ind->cur_node ++]);
89 else
90 return (NULL);
91}
92
93
94/*
95 * 'mxmlIndexFind()' - Find the next matching node.
96 *
97 * You should call mxmlIndexReset() prior to using this function for
98 * the first time with a particular set of "element" and "value"
99 * strings. Passing NULL for both "element" and "value" is equivalent
100 * to calling mxmlIndexEnum().
101 */
102
103mxml_node_t * /* O - Node or NULL if none found */
104mxmlIndexFind(mxml_index_t *ind, /* I - Index to search */
105 const char *element, /* I - Element name to find, if any */
106 const char *value) /* I - Attribute value, if any */
107{
108 int diff, /* Difference between names */
109 current, /* Current entity in search */
110 first, /* First entity in search */
111 last; /* Last entity in search */
112
113
114#ifdef DEBUG
115 printf("mxmlIndexFind(ind=%p, element=\"%s\", value=\"%s\")\n",
116 ind, element ? element : "(null)", value ? value : "(null)");
117#endif /* DEBUG */
118
119 /*
120 * Range check input...
121 */
122
123 if (!ind || (!ind->attr && value))
124 {
125#ifdef DEBUG
126 puts(" returning NULL...");
127 printf(" ind->attr=\"%s\"\n", ind->attr ? ind->attr : "(null)");
128#endif /* DEBUG */
129
130 return (NULL);
131 }
132
133 /*
134 * If both element and value are NULL, just enumerate the nodes in the
135 * index...
136 */
137
138 if (!element && !value)
139 return (mxmlIndexEnum(ind));
140
141 /*
142 * If there are no nodes in the index, return NULL...
143 */
144
145 if (!ind->num_nodes)
146 {
147#ifdef DEBUG
148 puts(" returning NULL...");
149 puts(" no nodes!");
150#endif /* DEBUG */
151
152 return (NULL);
153 }
154
155 /*
156 * If cur_node == 0, then find the first matching node...
157 */
158
159 if (ind->cur_node == 0)
160 {
161 /*
162 * Find the first node using a modified binary search algorithm...
163 */
164
165 first = 0;
166 last = ind->num_nodes - 1;
167
168#ifdef DEBUG
169 printf(" find first time, num_nodes=%d...\n", ind->num_nodes);
170#endif /* DEBUG */
171
172 while ((last - first) > 1)
173 {
174 current = (first + last) / 2;
175
176#ifdef DEBUG
177 printf(" first=%d, last=%d, current=%d\n", first, last, current);
178#endif /* DEBUG */
179
180 if ((diff = index_find(ind, element, value, ind->nodes[current])) == 0)
181 {
182 /*
183 * Found a match, move back to find the first...
184 */
185
186#ifdef DEBUG
187 puts(" match!");
188#endif /* DEBUG */
189
190 while (current > 0 &&
191 !index_find(ind, element, value, ind->nodes[current - 1]))
192 current --;
193
194#ifdef DEBUG
195 printf(" returning first match=%d\n", current);
196#endif /* DEBUG */
197
198 /*
199 * Return the first match and save the index to the next...
200 */
201
202 ind->cur_node = current + 1;
203
204 return (ind->nodes[current]);
205 }
206 else if (diff < 0)
207 last = current;
208 else
209 first = current;
210
211#ifdef DEBUG
212 printf(" diff=%d\n", diff);
213#endif /* DEBUG */
214 }
215
216 /*
217 * If we get this far, then we found exactly 0 or 1 matches...
218 */
219
220 for (current = first; current <= last; current ++)
221 if (!index_find(ind, element, value, ind->nodes[current]))
222 {
223 /*
224 * Found exactly one (or possibly two) match...
225 */
226
227#ifdef DEBUG
228 printf(" returning only match %d...\n", current);
229#endif /* DEBUG */
230
231 ind->cur_node = current + 1;
232
233 return (ind->nodes[current]);
234 }
235
236 /*
237 * No matches...
238 */
239
240 ind->cur_node = ind->num_nodes;
241
242#ifdef DEBUG
243 puts(" returning NULL...");
244#endif /* DEBUG */
245
246 return (NULL);
247 }
248 else if (ind->cur_node < ind->num_nodes &&
249 !index_find(ind, element, value, ind->nodes[ind->cur_node]))
250 {
251 /*
252 * Return the next matching node...
253 */
254
255#ifdef DEBUG
256 printf(" returning next match %d...\n", ind->cur_node);
257#endif /* DEBUG */
258
259 return (ind->nodes[ind->cur_node ++]);
260 }
261
262 /*
263 * If we get this far, then we have no matches...
264 */
265
266 ind->cur_node = ind->num_nodes;
267
268#ifdef DEBUG
269 puts(" returning NULL...");
270#endif /* DEBUG */
271
272 return (NULL);
273}
274
275
276/*
277 * 'mxmlIndexGetCount()' - Get the number of nodes in an index.
278 *
279 * @since Mini-XML 2.7@
280 */
281
282int /* I - Number of nodes in index */
283mxmlIndexGetCount(mxml_index_t *ind) /* I - Index of nodes */
284{
285 /*
286 * Range check input...
287 */
288
289 if (!ind)
290 return (0);
291
292 /*
293 * Return the number of nodes in the index...
294 */
295
296 return (ind->num_nodes);
297}
298
299
300/*
301 * 'mxmlIndexNew()' - Create a new index.
302 *
303 * The index will contain all nodes that contain the named element and/or
304 * attribute. If both "element" and "attr" are NULL, then the index will
305 * contain a sorted list of the elements in the node tree. Nodes are
306 * sorted by element name and optionally by attribute value if the "attr"
307 * argument is not NULL.
308 */
309
310mxml_index_t * /* O - New index */
311mxmlIndexNew(mxml_node_t *node, /* I - XML node tree */
312 const char *element, /* I - Element to index or NULL for all */
313 const char *attr) /* I - Attribute to index or NULL for none */
314{
315 mxml_index_t *ind; /* New index */
316 mxml_node_t *current, /* Current node in index */
317 **temp; /* Temporary node pointer array */
318
319
320 /*
321 * Range check input...
322 */
323
324#ifdef DEBUG
325 printf("mxmlIndexNew(node=%p, element=\"%s\", attr=\"%s\")\n",
326 node, element ? element : "(null)", attr ? attr : "(null)");
327#endif /* DEBUG */
328
329 if (!node)
330 return (NULL);
331
332 /*
333 * Create a new index...
334 */
335
336 if ((ind = calloc(1, sizeof(mxml_index_t))) == NULL)
337 {
338 mxml_error("Unable to allocate %d bytes for index - %s",
339 sizeof(mxml_index_t), strerror(errno));
340 return (NULL);
341 }
342
343 if (attr)
344 ind->attr = strdup(attr);
345
346 if (!element && !attr)
347 current = node;
348 else
349 current = mxmlFindElement(node, node, element, attr, NULL, MXML_DESCEND);
350
351 while (current)
352 {
353 if (ind->num_nodes >= ind->alloc_nodes)
354 {
355 if (!ind->alloc_nodes)
356 temp = malloc(64 * sizeof(mxml_node_t *));
357 else
358 temp = realloc(ind->nodes, (ind->alloc_nodes + 64) * sizeof(mxml_node_t *));
359
360 if (!temp)
361 {
362 /*
363 * Unable to allocate memory for the index, so abort...
364 */
365
366 mxml_error("Unable to allocate %d bytes for index: %s",
367 (ind->alloc_nodes + 64) * sizeof(mxml_node_t *),
368 strerror(errno));
369
370 mxmlIndexDelete(ind);
371 return (NULL);
372 }
373
374 ind->nodes = temp;
375 ind->alloc_nodes += 64;
376 }
377
378 ind->nodes[ind->num_nodes ++] = current;
379
380 current = mxmlFindElement(current, node, element, attr, NULL, MXML_DESCEND);
381 }
382
383 /*
384 * Sort nodes based upon the search criteria...
385 */
386
387#ifdef DEBUG
388 {
389 int i; /* Looping var */
390
391
392 printf("%d node(s) in index.\n\n", ind->num_nodes);
393
394 if (attr)
395 {
396 printf("Node Address Element %s\n", attr);
397 puts("-------- -------- -------------- ------------------------------");
398
399 for (i = 0; i < ind->num_nodes; i ++)
400 printf("%8d %-8p %-14.14s %s\n", i, ind->nodes[i],
401 ind->nodes[i]->value.element.name,
402 mxmlElementGetAttr(ind->nodes[i], attr));
403 }
404 else
405 {
406 puts("Node Address Element");
407 puts("-------- -------- --------------");
408
409 for (i = 0; i < ind->num_nodes; i ++)
410 printf("%8d %-8p %s\n", i, ind->nodes[i],
411 ind->nodes[i]->value.element.name);
412 }
413
414 putchar('\n');
415 }
416#endif /* DEBUG */
417
418 if (ind->num_nodes > 1)
419 index_sort(ind, 0, ind->num_nodes - 1);
420
421#ifdef DEBUG
422 {
423 int i; /* Looping var */
424
425
426 puts("After sorting:\n");
427
428 if (attr)
429 {
430 printf("Node Address Element %s\n", attr);
431 puts("-------- -------- -------------- ------------------------------");
432
433 for (i = 0; i < ind->num_nodes; i ++)
434 printf("%8d %-8p %-14.14s %s\n", i, ind->nodes[i],
435 ind->nodes[i]->value.element.name,
436 mxmlElementGetAttr(ind->nodes[i], attr));
437 }
438 else
439 {
440 puts("Node Address Element");
441 puts("-------- -------- --------------");
442
443 for (i = 0; i < ind->num_nodes; i ++)
444 printf("%8d %-8p %s\n", i, ind->nodes[i],
445 ind->nodes[i]->value.element.name);
446 }
447
448 putchar('\n');
449 }
450#endif /* DEBUG */
451
452 /*
453 * Return the new index...
454 */
455
456 return (ind);
457}
458
459
460/*
461 * 'mxmlIndexReset()' - Reset the enumeration/find pointer in the index and
462 * return the first node in the index.
463 *
464 * This function should be called prior to using mxmlIndexEnum() or
465 * mxmlIndexFind() for the first time.
466 */
467
468mxml_node_t * /* O - First node or NULL if there is none */
469mxmlIndexReset(mxml_index_t *ind) /* I - Index to reset */
470{
471#ifdef DEBUG
472 printf("mxmlIndexReset(ind=%p)\n", ind);
473#endif /* DEBUG */
474
475 /*
476 * Range check input...
477 */
478
479 if (!ind)
480 return (NULL);
481
482 /*
483 * Set the index to the first element...
484 */
485
486 ind->cur_node = 0;
487
488 /*
489 * Return the first node...
490 */
491
492 if (ind->num_nodes)
493 return (ind->nodes[0]);
494 else
495 return (NULL);
496}
497
498
499/*
500 * 'index_compare()' - Compare two nodes.
501 */
502
503static int /* O - Result of comparison */
504index_compare(mxml_index_t *ind, /* I - Index */
505 mxml_node_t *first, /* I - First node */
506 mxml_node_t *second) /* I - Second node */
507{
508 int diff; /* Difference */
509
510
511 /*
512 * Check the element name...
513 */
514
515 if ((diff = strcmp(first->value.element.name,
516 second->value.element.name)) != 0)
517 return (diff);
518
519 /*
520 * Check the attribute value...
521 */
522
523 if (ind->attr)
524 {
525 if ((diff = strcmp(mxmlElementGetAttr(first, ind->attr),
526 mxmlElementGetAttr(second, ind->attr))) != 0)
527 return (diff);
528 }
529
530 /*
531 * No difference, return 0...
532 */
533
534 return (0);
535}
536
537
538/*
539 * 'index_find()' - Compare a node with index values.
540 */
541
542static int /* O - Result of comparison */
543index_find(mxml_index_t *ind, /* I - Index */
544 const char *element, /* I - Element name or NULL */
545 const char *value, /* I - Attribute value or NULL */
546 mxml_node_t *node) /* I - Node */
547{
548 int diff; /* Difference */
549
550
551 /*
552 * Check the element name...
553 */
554
555 if (element)
556 {
557 if ((diff = strcmp(element, node->value.element.name)) != 0)
558 return (diff);
559 }
560
561 /*
562 * Check the attribute value...
563 */
564
565 if (value)
566 {
567 if ((diff = strcmp(value, mxmlElementGetAttr(node, ind->attr))) != 0)
568 return (diff);
569 }
570
571 /*
572 * No difference, return 0...
573 */
574
575 return (0);
576}
577
578
579/*
580 * 'index_sort()' - Sort the nodes in the index...
581 *
582 * This function implements the classic quicksort algorithm...
583 */
584
585static void
586index_sort(mxml_index_t *ind, /* I - Index to sort */
587 int left, /* I - Left node in partition */
588 int right) /* I - Right node in partition */
589{
590 mxml_node_t *pivot, /* Pivot node */
591 *temp; /* Swap node */
592 int templ, /* Temporary left node */
593 tempr; /* Temporary right node */
594
595
596 /*
597 * Loop until we have sorted all the way to the right...
598 */
599
600 do
601 {
602 /*
603 * Sort the pivot in the current partition...
604 */
605
606 pivot = ind->nodes[left];
607
608 for (templ = left, tempr = right; templ < tempr;)
609 {
610 /*
611 * Move left while left node <= pivot node...
612 */
613
614 while ((templ < right) &&
615 index_compare(ind, ind->nodes[templ], pivot) <= 0)
616 templ ++;
617
618 /*
619 * Move right while right node > pivot node...
620 */
621
622 while ((tempr > left) &&
623 index_compare(ind, ind->nodes[tempr], pivot) > 0)
624 tempr --;
625
626 /*
627 * Swap nodes if needed...
628 */
629
630 if (templ < tempr)
631 {
632 temp = ind->nodes[templ];
633 ind->nodes[templ] = ind->nodes[tempr];
634 ind->nodes[tempr] = temp;
635 }
636 }
637
638 /*
639 * When we get here, the right (tempr) node is the new position for the
640 * pivot node...
641 */
642
643 if (index_compare(ind, pivot, ind->nodes[tempr]) > 0)
644 {
645 ind->nodes[left] = ind->nodes[tempr];
646 ind->nodes[tempr] = pivot;
647 }
648
649 /*
650 * Recursively sort the left partition as needed...
651 */
652
653 if (left < (tempr - 1))
654 index_sort(ind, left, tempr - 1);
655 }
656 while (right > (left = tempr + 1));
657}
658
659
660/*
661 * End of "$Id: mxml-index.c 426 2011-01-01 23:42:17Z mike $".
662 */
diff --git a/tools/gator/daemon/mxml/mxml-node.c b/tools/gator/daemon/mxml/mxml-node.c
new file mode 100644
index 00000000000..44af759f9de
--- /dev/null
+++ b/tools/gator/daemon/mxml/mxml-node.c
@@ -0,0 +1,807 @@
1/*
2 * "$Id: mxml-node.c 436 2011-01-22 01:02:05Z mike $"
3 *
4 * Node support code for Mini-XML, a small XML-like file parsing library.
5 *
6 * Copyright 2003-2011 by Michael R Sweet.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Michael R Sweet and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "COPYING"
11 * which should have been included with this file. If this file is
12 * missing or damaged, see the license at:
13 *
14 * http://www.minixml.org/
15 *
16 * Contents:
17 *
18 * mxmlAdd() - Add a node to a tree.
19 * mxmlDelete() - Delete a node and all of its children.
20 * mxmlGetRefCount() - Get the current reference (use) count for a node.
21 * mxmlNewCDATA() - Create a new CDATA node.
22 * mxmlNewCustom() - Create a new custom data node.
23 * mxmlNewElement() - Create a new element node.
24 * mxmlNewInteger() - Create a new integer node.
25 * mxmlNewOpaque() - Create a new opaque string.
26 * mxmlNewReal() - Create a new real number node.
27 * mxmlNewText() - Create a new text fragment node.
28 * mxmlNewTextf() - Create a new formatted text fragment node.
29 * mxmlRemove() - Remove a node from its parent.
30 * mxmlNewXML() - Create a new XML document tree.
31 * mxmlRelease() - Release a node.
32 * mxmlRetain() - Retain a node.
33 * mxml_new() - Create a new node.
34 */
35
36/*
37 * Include necessary headers...
38 */
39
40#include "config.h"
41#include "mxml.h"
42
43
44/*
45 * Local functions...
46 */
47
48static mxml_node_t *mxml_new(mxml_node_t *parent, mxml_type_t type);
49
50
51/*
52 * 'mxmlAdd()' - Add a node to a tree.
53 *
54 * Adds the specified node to the parent. If the child argument is not
55 * NULL, puts the new node before or after the specified child depending
56 * on the value of the where argument. If the child argument is NULL,
57 * puts the new node at the beginning of the child list (MXML_ADD_BEFORE)
58 * or at the end of the child list (MXML_ADD_AFTER). The constant
59 * MXML_ADD_TO_PARENT can be used to specify a NULL child pointer.
60 */
61
62void
63mxmlAdd(mxml_node_t *parent, /* I - Parent node */
64 int where, /* I - Where to add, MXML_ADD_BEFORE or MXML_ADD_AFTER */
65 mxml_node_t *child, /* I - Child node for where or MXML_ADD_TO_PARENT */
66 mxml_node_t *node) /* I - Node to add */
67{
68#ifdef DEBUG
69 fprintf(stderr, "mxmlAdd(parent=%p, where=%d, child=%p, node=%p)\n", parent,
70 where, child, node);
71#endif /* DEBUG */
72
73 /*
74 * Range check input...
75 */
76
77 if (!parent || !node)
78 return;
79
80#if DEBUG > 1
81 fprintf(stderr, " BEFORE: node->parent=%p\n", node->parent);
82 if (parent)
83 {
84 fprintf(stderr, " BEFORE: parent->child=%p\n", parent->child);
85 fprintf(stderr, " BEFORE: parent->last_child=%p\n", parent->last_child);
86 fprintf(stderr, " BEFORE: parent->prev=%p\n", parent->prev);
87 fprintf(stderr, " BEFORE: parent->next=%p\n", parent->next);
88 }
89#endif /* DEBUG > 1 */
90
91 /*
92 * Remove the node from any existing parent...
93 */
94
95 if (node->parent)
96 mxmlRemove(node);
97
98 /*
99 * Reset pointers...
100 */
101
102 node->parent = parent;
103
104 switch (where)
105 {
106 case MXML_ADD_BEFORE :
107 if (!child || child == parent->child || child->parent != parent)
108 {
109 /*
110 * Insert as first node under parent...
111 */
112
113 node->next = parent->child;
114
115 if (parent->child)
116 parent->child->prev = node;
117 else
118 parent->last_child = node;
119
120 parent->child = node;
121 }
122 else
123 {
124 /*
125 * Insert node before this child...
126 */
127
128 node->next = child;
129 node->prev = child->prev;
130
131 if (child->prev)
132 child->prev->next = node;
133 else
134 parent->child = node;
135
136 child->prev = node;
137 }
138 break;
139
140 case MXML_ADD_AFTER :
141 if (!child || child == parent->last_child || child->parent != parent)
142 {
143 /*
144 * Insert as last node under parent...
145 */
146
147 node->parent = parent;
148 node->prev = parent->last_child;
149
150 if (parent->last_child)
151 parent->last_child->next = node;
152 else
153 parent->child = node;
154
155 parent->last_child = node;
156 }
157 else
158 {
159 /*
160 * Insert node after this child...
161 */
162
163 node->prev = child;
164 node->next = child->next;
165
166 if (child->next)
167 child->next->prev = node;
168 else
169 parent->last_child = node;
170
171 child->next = node;
172 }
173 break;
174 }
175
176#if DEBUG > 1
177 fprintf(stderr, " AFTER: node->parent=%p\n", node->parent);
178 if (parent)
179 {
180 fprintf(stderr, " AFTER: parent->child=%p\n", parent->child);
181 fprintf(stderr, " AFTER: parent->last_child=%p\n", parent->last_child);
182 fprintf(stderr, " AFTER: parent->prev=%p\n", parent->prev);
183 fprintf(stderr, " AFTER: parent->next=%p\n", parent->next);
184 }
185#endif /* DEBUG > 1 */
186}
187
188
189/*
190 * 'mxmlDelete()' - Delete a node and all of its children.
191 *
192 * If the specified node has a parent, this function first removes the
193 * node from its parent using the mxmlRemove() function.
194 */
195
196void
197mxmlDelete(mxml_node_t *node) /* I - Node to delete */
198{
199 int i; /* Looping var */
200
201
202#ifdef DEBUG
203 fprintf(stderr, "mxmlDelete(node=%p)\n", node);
204#endif /* DEBUG */
205
206 /*
207 * Range check input...
208 */
209
210 if (!node)
211 return;
212
213 /*
214 * Remove the node from its parent, if any...
215 */
216
217 mxmlRemove(node);
218
219 /*
220 * Delete children...
221 */
222
223 while (node->child)
224 mxmlDelete(node->child);
225
226 /*
227 * Now delete any node data...
228 */
229
230 switch (node->type)
231 {
232 case MXML_ELEMENT :
233 if (node->value.element.name)
234 free(node->value.element.name);
235
236 if (node->value.element.num_attrs)
237 {
238 for (i = 0; i < node->value.element.num_attrs; i ++)
239 {
240 if (node->value.element.attrs[i].name)
241 free(node->value.element.attrs[i].name);
242 if (node->value.element.attrs[i].value)
243 free(node->value.element.attrs[i].value);
244 }
245
246 free(node->value.element.attrs);
247 }
248 break;
249 case MXML_INTEGER :
250 /* Nothing to do */
251 break;
252 case MXML_OPAQUE :
253 if (node->value.opaque)
254 free(node->value.opaque);
255 break;
256 case MXML_REAL :
257 /* Nothing to do */
258 break;
259 case MXML_TEXT :
260 if (node->value.text.string)
261 free(node->value.text.string);
262 break;
263 case MXML_CUSTOM :
264 if (node->value.custom.data &&
265 node->value.custom.destroy)
266 (*(node->value.custom.destroy))(node->value.custom.data);
267 break;
268 default :
269 break;
270 }
271
272 /*
273 * Free this node...
274 */
275
276 free(node);
277}
278
279
280/*
281 * 'mxmlGetRefCount()' - Get the current reference (use) count for a node.
282 *
283 * The initial reference count of new nodes is 1. Use the @link mxmlRetain@
284 * and @link mxmlRelease@ functions to increment and decrement a node's
285 * reference count.
286 *
287 * @since Mini-XML 2.7@.
288 */
289
290int /* O - Reference count */
291mxmlGetRefCount(mxml_node_t *node) /* I - Node */
292{
293 /*
294 * Range check input...
295 */
296
297 if (!node)
298 return (0);
299
300 /*
301 * Return the reference count...
302 */
303
304 return (node->ref_count);
305}
306
307
308/*
309 * 'mxmlNewCDATA()' - Create a new CDATA node.
310 *
311 * The new CDATA node is added to the end of the specified parent's child
312 * list. The constant MXML_NO_PARENT can be used to specify that the new
313 * CDATA node has no parent. The data string must be nul-terminated and
314 * is copied into the new node. CDATA nodes use the MXML_ELEMENT type.
315 *
316 * @since Mini-XML 2.3@
317 */
318
319mxml_node_t * /* O - New node */
320mxmlNewCDATA(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
321 const char *data) /* I - Data string */
322{
323 mxml_node_t *node; /* New node */
324
325
326#ifdef DEBUG
327 fprintf(stderr, "mxmlNewCDATA(parent=%p, data=\"%s\")\n",
328 parent, data ? data : "(null)");
329#endif /* DEBUG */
330
331 /*
332 * Range check input...
333 */
334
335 if (!data)
336 return (NULL);
337
338 /*
339 * Create the node and set the name value...
340 */
341
342 if ((node = mxml_new(parent, MXML_ELEMENT)) != NULL)
343 node->value.element.name = _mxml_strdupf("![CDATA[%s]]", data);
344
345 return (node);
346}
347
348
349/*
350 * 'mxmlNewCustom()' - Create a new custom data node.
351 *
352 * The new custom node is added to the end of the specified parent's child
353 * list. The constant MXML_NO_PARENT can be used to specify that the new
354 * element node has no parent. NULL can be passed when the data in the
355 * node is not dynamically allocated or is separately managed.
356 *
357 * @since Mini-XML 2.1@
358 */
359
360mxml_node_t * /* O - New node */
361mxmlNewCustom(
362 mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
363 void *data, /* I - Pointer to data */
364 mxml_custom_destroy_cb_t destroy) /* I - Function to destroy data */
365{
366 mxml_node_t *node; /* New node */
367
368
369#ifdef DEBUG
370 fprintf(stderr, "mxmlNewCustom(parent=%p, data=%p, destroy=%p)\n", parent,
371 data, destroy);
372#endif /* DEBUG */
373
374 /*
375 * Create the node and set the value...
376 */
377
378 if ((node = mxml_new(parent, MXML_CUSTOM)) != NULL)
379 {
380 node->value.custom.data = data;
381 node->value.custom.destroy = destroy;
382 }
383
384 return (node);
385}
386
387
388/*
389 * 'mxmlNewElement()' - Create a new element node.
390 *
391 * The new element node is added to the end of the specified parent's child
392 * list. The constant MXML_NO_PARENT can be used to specify that the new
393 * element node has no parent.
394 */
395
396mxml_node_t * /* O - New node */
397mxmlNewElement(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
398 const char *name) /* I - Name of element */
399{
400 mxml_node_t *node; /* New node */
401
402
403#ifdef DEBUG
404 fprintf(stderr, "mxmlNewElement(parent=%p, name=\"%s\")\n", parent,
405 name ? name : "(null)");
406#endif /* DEBUG */
407
408 /*
409 * Range check input...
410 */
411
412 if (!name)
413 return (NULL);
414
415 /*
416 * Create the node and set the element name...
417 */
418
419 if ((node = mxml_new(parent, MXML_ELEMENT)) != NULL)
420 node->value.element.name = strdup(name);
421
422 return (node);
423}
424
425
426/*
427 * 'mxmlNewInteger()' - Create a new integer node.
428 *
429 * The new integer node is added to the end of the specified parent's child
430 * list. The constant MXML_NO_PARENT can be used to specify that the new
431 * integer node has no parent.
432 */
433
434mxml_node_t * /* O - New node */
435mxmlNewInteger(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
436 int integer) /* I - Integer value */
437{
438 mxml_node_t *node; /* New node */
439
440
441#ifdef DEBUG
442 fprintf(stderr, "mxmlNewInteger(parent=%p, integer=%d)\n", parent, integer);
443#endif /* DEBUG */
444
445 /*
446 * Create the node and set the element name...
447 */
448
449 if ((node = mxml_new(parent, MXML_INTEGER)) != NULL)
450 node->value.integer = integer;
451
452 return (node);
453}
454
455
456/*
457 * 'mxmlNewOpaque()' - Create a new opaque string.
458 *
459 * The new opaque node is added to the end of the specified parent's child
460 * list. The constant MXML_NO_PARENT can be used to specify that the new
461 * opaque node has no parent. The opaque string must be nul-terminated and
462 * is copied into the new node.
463 */
464
465mxml_node_t * /* O - New node */
466mxmlNewOpaque(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
467 const char *opaque) /* I - Opaque string */
468{
469 mxml_node_t *node; /* New node */
470
471
472#ifdef DEBUG
473 fprintf(stderr, "mxmlNewOpaque(parent=%p, opaque=\"%s\")\n", parent,
474 opaque ? opaque : "(null)");
475#endif /* DEBUG */
476
477 /*
478 * Range check input...
479 */
480
481 if (!opaque)
482 return (NULL);
483
484 /*
485 * Create the node and set the element name...
486 */
487
488 if ((node = mxml_new(parent, MXML_OPAQUE)) != NULL)
489 node->value.opaque = strdup(opaque);
490
491 return (node);
492}
493
494
495/*
496 * 'mxmlNewReal()' - Create a new real number node.
497 *
498 * The new real number node is added to the end of the specified parent's
499 * child list. The constant MXML_NO_PARENT can be used to specify that
500 * the new real number node has no parent.
501 */
502
503mxml_node_t * /* O - New node */
504mxmlNewReal(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
505 double real) /* I - Real number value */
506{
507 mxml_node_t *node; /* New node */
508
509
510#ifdef DEBUG
511 fprintf(stderr, "mxmlNewReal(parent=%p, real=%g)\n", parent, real);
512#endif /* DEBUG */
513
514 /*
515 * Create the node and set the element name...
516 */
517
518 if ((node = mxml_new(parent, MXML_REAL)) != NULL)
519 node->value.real = real;
520
521 return (node);
522}
523
524
525/*
526 * 'mxmlNewText()' - Create a new text fragment node.
527 *
528 * The new text node is added to the end of the specified parent's child
529 * list. The constant MXML_NO_PARENT can be used to specify that the new
530 * text node has no parent. The whitespace parameter is used to specify
531 * whether leading whitespace is present before the node. The text
532 * string must be nul-terminated and is copied into the new node.
533 */
534
535mxml_node_t * /* O - New node */
536mxmlNewText(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
537 int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */
538 const char *string) /* I - String */
539{
540 mxml_node_t *node; /* New node */
541
542
543#ifdef DEBUG
544 fprintf(stderr, "mxmlNewText(parent=%p, whitespace=%d, string=\"%s\")\n",
545 parent, whitespace, string ? string : "(null)");
546#endif /* DEBUG */
547
548 /*
549 * Range check input...
550 */
551
552 if (!string)
553 return (NULL);
554
555 /*
556 * Create the node and set the text value...
557 */
558
559 if ((node = mxml_new(parent, MXML_TEXT)) != NULL)
560 {
561 node->value.text.whitespace = whitespace;
562 node->value.text.string = strdup(string);
563 }
564
565 return (node);
566}
567
568
569/*
570 * 'mxmlNewTextf()' - Create a new formatted text fragment node.
571 *
572 * The new text node is added to the end of the specified parent's child
573 * list. The constant MXML_NO_PARENT can be used to specify that the new
574 * text node has no parent. The whitespace parameter is used to specify
575 * whether leading whitespace is present before the node. The format
576 * string must be nul-terminated and is formatted into the new node.
577 */
578
579mxml_node_t * /* O - New node */
580mxmlNewTextf(mxml_node_t *parent, /* I - Parent node or MXML_NO_PARENT */
581 int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */
582 const char *format, /* I - Printf-style frmat string */
583 ...) /* I - Additional args as needed */
584{
585 mxml_node_t *node; /* New node */
586 va_list ap; /* Pointer to arguments */
587
588
589#ifdef DEBUG
590 fprintf(stderr, "mxmlNewTextf(parent=%p, whitespace=%d, format=\"%s\", ...)\n",
591 parent, whitespace, format ? format : "(null)");
592#endif /* DEBUG */
593
594 /*
595 * Range check input...
596 */
597
598 if (!format)
599 return (NULL);
600
601 /*
602 * Create the node and set the text value...
603 */
604
605 if ((node = mxml_new(parent, MXML_TEXT)) != NULL)
606 {
607 va_start(ap, format);
608
609 node->value.text.whitespace = whitespace;
610 node->value.text.string = _mxml_vstrdupf(format, ap);
611
612 va_end(ap);
613 }
614
615 return (node);
616}
617
618
619/*
620 * 'mxmlRemove()' - Remove a node from its parent.
621 *
622 * Does not free memory used by the node - use mxmlDelete() for that.
623 * This function does nothing if the node has no parent.
624 */
625
626void
627mxmlRemove(mxml_node_t *node) /* I - Node to remove */
628{
629#ifdef DEBUG
630 fprintf(stderr, "mxmlRemove(node=%p)\n", node);
631#endif /* DEBUG */
632
633 /*
634 * Range check input...
635 */
636
637 if (!node || !node->parent)
638 return;
639
640 /*
641 * Remove from parent...
642 */
643
644#if DEBUG > 1
645 fprintf(stderr, " BEFORE: node->parent=%p\n", node->parent);
646 if (node->parent)
647 {
648 fprintf(stderr, " BEFORE: node->parent->child=%p\n", node->parent->child);
649 fprintf(stderr, " BEFORE: node->parent->last_child=%p\n", node->parent->last_child);
650 }
651 fprintf(stderr, " BEFORE: node->child=%p\n", node->child);
652 fprintf(stderr, " BEFORE: node->last_child=%p\n", node->last_child);
653 fprintf(stderr, " BEFORE: node->prev=%p\n", node->prev);
654 fprintf(stderr, " BEFORE: node->next=%p\n", node->next);
655#endif /* DEBUG > 1 */
656
657 if (node->prev)
658 node->prev->next = node->next;
659 else
660 node->parent->child = node->next;
661
662 if (node->next)
663 node->next->prev = node->prev;
664 else
665 node->parent->last_child = node->prev;
666
667 node->parent = NULL;
668 node->prev = NULL;
669 node->next = NULL;
670
671#if DEBUG > 1
672 fprintf(stderr, " AFTER: node->parent=%p\n", node->parent);
673 if (node->parent)
674 {
675 fprintf(stderr, " AFTER: node->parent->child=%p\n", node->parent->child);
676 fprintf(stderr, " AFTER: node->parent->last_child=%p\n", node->parent->last_child);
677 }
678 fprintf(stderr, " AFTER: node->child=%p\n", node->child);
679 fprintf(stderr, " AFTER: node->last_child=%p\n", node->last_child);
680 fprintf(stderr, " AFTER: node->prev=%p\n", node->prev);
681 fprintf(stderr, " AFTER: node->next=%p\n", node->next);
682#endif /* DEBUG > 1 */
683}
684
685
686/*
687 * 'mxmlNewXML()' - Create a new XML document tree.
688 *
689 * The "version" argument specifies the version number to put in the
690 * ?xml element node. If NULL, version 1.0 is assumed.
691 *
692 * @since Mini-XML 2.3@
693 */
694
695mxml_node_t * /* O - New ?xml node */
696mxmlNewXML(const char *version) /* I - Version number to use */
697{
698 char element[1024]; /* Element text */
699
700
701 snprintf(element, sizeof(element), "?xml version=\"%s\" encoding=\"utf-8\"?",
702 version ? version : "1.0");
703
704 return (mxmlNewElement(NULL, element));
705}
706
707
708/*
709 * 'mxmlRelease()' - Release a node.
710 *
711 * When the reference count reaches zero, the node (and any children)
712 * is deleted via mxmlDelete().
713 *
714 * @since Mini-XML 2.3@
715 */
716
717int /* O - New reference count */
718mxmlRelease(mxml_node_t *node) /* I - Node */
719{
720 if (node)
721 {
722 if ((-- node->ref_count) <= 0)
723 {
724 mxmlDelete(node);
725 return (0);
726 }
727 else
728 return (node->ref_count);
729 }
730 else
731 return (-1);
732}
733
734
735/*
736 * 'mxmlRetain()' - Retain a node.
737 *
738 * @since Mini-XML 2.3@
739 */
740
741int /* O - New reference count */
742mxmlRetain(mxml_node_t *node) /* I - Node */
743{
744 if (node)
745 return (++ node->ref_count);
746 else
747 return (-1);
748}
749
750
751/*
752 * 'mxml_new()' - Create a new node.
753 */
754
755static mxml_node_t * /* O - New node */
756mxml_new(mxml_node_t *parent, /* I - Parent node */
757 mxml_type_t type) /* I - Node type */
758{
759 mxml_node_t *node; /* New node */
760
761
762#if DEBUG > 1
763 fprintf(stderr, "mxml_new(parent=%p, type=%d)\n", parent, type);
764#endif /* DEBUG > 1 */
765
766 /*
767 * Allocate memory for the node...
768 */
769
770 if ((node = calloc(1, sizeof(mxml_node_t))) == NULL)
771 {
772#if DEBUG > 1
773 fputs(" returning NULL\n", stderr);
774#endif /* DEBUG > 1 */
775
776 return (NULL);
777 }
778
779#if DEBUG > 1
780 fprintf(stderr, " returning %p\n", node);
781#endif /* DEBUG > 1 */
782
783 /*
784 * Set the node type...
785 */
786
787 node->type = type;
788 node->ref_count = 1;
789
790 /*
791 * Add to the parent if present...
792 */
793
794 if (parent)
795 mxmlAdd(parent, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, node);
796
797 /*
798 * Return the new node...
799 */
800
801 return (node);
802}
803
804
805/*
806 * End of "$Id: mxml-node.c 436 2011-01-22 01:02:05Z mike $".
807 */
diff --git a/tools/gator/daemon/mxml/mxml-private.c b/tools/gator/daemon/mxml/mxml-private.c
new file mode 100644
index 00000000000..72f3e2320c7
--- /dev/null
+++ b/tools/gator/daemon/mxml/mxml-private.c
@@ -0,0 +1,331 @@
1/*
2 * "$Id: mxml-private.c 422 2010-11-07 22:55:11Z mike $"
3 *
4 * Private functions for Mini-XML, a small XML-like file parsing library.
5 *
6 * Copyright 2003-2010 by Michael R Sweet.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Michael R Sweet and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "COPYING"
11 * which should have been included with this file. If this file is
12 * missing or damaged, see the license at:
13 *
14 * http://www.minixml.org/
15 *
16 * Contents:
17 *
18 * mxml_error() - Display an error message.
19 * mxml_integer_cb() - Default callback for integer values.
20 * mxml_opaque_cb() - Default callback for opaque values.
21 * mxml_real_cb() - Default callback for real number values.
22 * _mxml_global() - Get global data.
23 */
24
25/*
26 * Include necessary headers...
27 */
28
29#include "mxml-private.h"
30
31
32/*
33 * Some crazy people think that unloading a shared object is a good or safe
34 * thing to do. Unfortunately, most objects are simply *not* safe to unload
35 * and bad things *will* happen.
36 *
37 * The following mess of conditional code allows us to provide a destructor
38 * function in Mini-XML for our thread-global storage so that it can possibly
39 * be unloaded safely, although since there is no standard way to do so I
40 * can't even provide any guarantees that you can do it safely on all platforms.
41 *
42 * This code currently supports AIX, HP-UX, Linux, Mac OS X, Solaris, and
43 * Windows. It might work on the BSDs and IRIX, but I haven't tested that.
44 */
45
46#if defined(__sun) || defined(_AIX)
47# pragma fini(_mxml_fini)
48# define _MXML_FINI _mxml_fini
49#elif defined(__hpux)
50# pragma FINI _mxml_fini
51# define _MXML_FINI _mxml_fini
52#elif defined(__GNUC__) /* Linux and Mac OS X */
53# define _MXML_FINI __attribute((destructor)) _mxml_fini
54#else
55# define _MXML_FINI _fini
56#endif /* __sun */
57
58
59/*
60 * 'mxml_error()' - Display an error message.
61 */
62
63void
64mxml_error(const char *format, /* I - Printf-style format string */
65 ...) /* I - Additional arguments as needed */
66{
67 va_list ap; /* Pointer to arguments */
68 char s[1024]; /* Message string */
69 _mxml_global_t *global = _mxml_global();
70 /* Global data */
71
72
73 /*
74 * Range check input...
75 */
76
77 if (!format)
78 return;
79
80 /*
81 * Format the error message string...
82 */
83
84 va_start(ap, format);
85
86 vsnprintf(s, sizeof(s), format, ap);
87
88 va_end(ap);
89
90 /*
91 * And then display the error message...
92 */
93
94 if (global->error_cb)
95 (*global->error_cb)(s);
96 else
97 fprintf(stderr, "mxml: %s\n", s);
98}
99
100
101/*
102 * 'mxml_ignore_cb()' - Default callback for ignored values.
103 */
104
105mxml_type_t /* O - Node type */
106mxml_ignore_cb(mxml_node_t *node) /* I - Current node */
107{
108 (void)node;
109
110 return (MXML_IGNORE);
111}
112
113
114/*
115 * 'mxml_integer_cb()' - Default callback for integer values.
116 */
117
118mxml_type_t /* O - Node type */
119mxml_integer_cb(mxml_node_t *node) /* I - Current node */
120{
121 (void)node;
122
123 return (MXML_INTEGER);
124}
125
126
127/*
128 * 'mxml_opaque_cb()' - Default callback for opaque values.
129 */
130
131mxml_type_t /* O - Node type */
132mxml_opaque_cb(mxml_node_t *node) /* I - Current node */
133{
134 (void)node;
135
136 return (MXML_OPAQUE);
137}
138
139
140/*
141 * 'mxml_real_cb()' - Default callback for real number values.
142 */
143
144mxml_type_t /* O - Node type */
145mxml_real_cb(mxml_node_t *node) /* I - Current node */
146{
147 (void)node;
148
149 return (MXML_REAL);
150}
151
152
153#ifdef HAVE_PTHREAD_H /**** POSIX threading ****/
154# include <pthread.h>
155
156static pthread_key_t _mxml_key = -1; /* Thread local storage key */
157static pthread_once_t _mxml_key_once = PTHREAD_ONCE_INIT;
158 /* One-time initialization object */
159static void _mxml_init(void);
160static void _mxml_destructor(void *g);
161
162
163/*
164 * '_mxml_destructor()' - Free memory used for globals...
165 */
166
167static void
168_mxml_destructor(void *g) /* I - Global data */
169{
170 free(g);
171}
172
173
174/*
175 * '_mxml_fini()' - Clean up when unloaded.
176 */
177
178static void
179_MXML_FINI(void)
180{
181 _mxml_global_t *global; /* Global data */
182
183
184 if (_mxml_key != -1)
185 {
186 if ((global = (_mxml_global_t *)pthread_getspecific(_mxml_key)) != NULL)
187 _mxml_destructor(global);
188
189 pthread_key_delete(_mxml_key);
190 _mxml_key = -1;
191 }
192}
193
194
195/*
196 * '_mxml_global()' - Get global data.
197 */
198
199_mxml_global_t * /* O - Global data */
200_mxml_global(void)
201{
202 _mxml_global_t *global; /* Global data */
203
204
205 pthread_once(&_mxml_key_once, _mxml_init);
206
207 if ((global = (_mxml_global_t *)pthread_getspecific(_mxml_key)) == NULL)
208 {
209 global = (_mxml_global_t *)calloc(1, sizeof(_mxml_global_t));
210 pthread_setspecific(_mxml_key, global);
211
212 global->num_entity_cbs = 1;
213 global->entity_cbs[0] = _mxml_entity_cb;
214 global->wrap = 72;
215 }
216
217 return (global);
218}
219
220
221/*
222 * '_mxml_init()' - Initialize global data...
223 */
224
225static void
226_mxml_init(void)
227{
228 pthread_key_create(&_mxml_key, _mxml_destructor);
229}
230
231
232#elif defined(WIN32) && defined(MXML1_EXPORTS) /**** WIN32 threading ****/
233# include <windows.h>
234
235static DWORD _mxml_tls_index; /* Index for global storage */
236
237
238/*
239 * 'DllMain()' - Main entry for library.
240 */
241
242BOOL WINAPI /* O - Success/failure */
243DllMain(HINSTANCE hinst, /* I - DLL module handle */
244 DWORD reason, /* I - Reason */
245 LPVOID reserved) /* I - Unused */
246{
247 _mxml_global_t *global; /* Global data */
248
249
250 (void)hinst;
251 (void)reserved;
252
253 switch (reason)
254 {
255 case DLL_PROCESS_ATTACH : /* Called on library initialization */
256 if ((_mxml_tls_index = TlsAlloc()) == TLS_OUT_OF_INDEXES)
257 return (FALSE);
258 break;
259
260 case DLL_THREAD_DETACH : /* Called when a thread terminates */
261 if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) != NULL)
262 free(global);
263 break;
264
265 case DLL_PROCESS_DETACH : /* Called when library is unloaded */
266 if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) != NULL)
267 free(global);
268
269 TlsFree(_mxml_tls_index);
270 break;
271
272 default:
273 break;
274 }
275
276 return (TRUE);
277}
278
279
280/*
281 * '_mxml_global()' - Get global data.
282 */
283
284_mxml_global_t * /* O - Global data */
285_mxml_global(void)
286{
287 _mxml_global_t *global; /* Global data */
288
289
290 if ((global = (_mxml_global_t *)TlsGetValue(_mxml_tls_index)) == NULL)
291 {
292 global = (_mxml_global_t *)calloc(1, sizeof(_mxml_global_t));
293
294 global->num_entity_cbs = 1;
295 global->entity_cbs[0] = _mxml_entity_cb;
296 global->wrap = 72;
297
298 TlsSetValue(_mxml_tls_index, (LPVOID)global);
299 }
300
301 return (global);
302}
303
304
305#else /**** No threading ****/
306/*
307 * '_mxml_global()' - Get global data.
308 */
309
310_mxml_global_t * /* O - Global data */
311_mxml_global(void)
312{
313 static _mxml_global_t global = /* Global data */
314 {
315 NULL, /* error_cb */
316 1, /* num_entity_cbs */
317 { _mxml_entity_cb }, /* entity_cbs */
318 72, /* wrap */
319 NULL, /* custom_load_cb */
320 NULL /* custom_save_cb */
321 };
322
323
324 return (&global);
325}
326#endif /* HAVE_PTHREAD_H */
327
328
329/*
330 * End of "$Id: mxml-private.c 422 2010-11-07 22:55:11Z mike $".
331 */
diff --git a/tools/gator/daemon/mxml/mxml-private.h b/tools/gator/daemon/mxml/mxml-private.h
new file mode 100644
index 00000000000..8789e6c52cb
--- /dev/null
+++ b/tools/gator/daemon/mxml/mxml-private.h
@@ -0,0 +1,50 @@
1/*
2 * "$Id: mxml-private.h 408 2010-09-19 05:26:46Z mike $"
3 *
4 * Private definitions for Mini-XML, a small XML-like file parsing library.
5 *
6 * Copyright 2003-2010 by Michael R Sweet.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Michael R Sweet and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "COPYING"
11 * which should have been included with this file. If this file is
12 * missing or damaged, see the license at:
13 *
14 * http://www.minixml.org/
15 */
16
17/*
18 * Include necessary headers...
19 */
20
21#include "config.h"
22#include "mxml.h"
23
24
25/*
26 * Global, per-thread data...
27 */
28
29typedef struct _mxml_global_s
30{
31 void (*error_cb)(const char *);
32 int num_entity_cbs;
33 int (*entity_cbs[100])(const char *name);
34 int wrap;
35 mxml_custom_load_cb_t custom_load_cb;
36 mxml_custom_save_cb_t custom_save_cb;
37} _mxml_global_t;
38
39
40/*
41 * Functions...
42 */
43
44extern _mxml_global_t *_mxml_global(void);
45extern int _mxml_entity_cb(const char *name);
46
47
48/*
49 * End of "$Id: mxml-private.h 408 2010-09-19 05:26:46Z mike $".
50 */
diff --git a/tools/gator/daemon/mxml/mxml-search.c b/tools/gator/daemon/mxml/mxml-search.c
new file mode 100644
index 00000000000..f975af1543c
--- /dev/null
+++ b/tools/gator/daemon/mxml/mxml-search.c
@@ -0,0 +1,287 @@
1/*
2 * "$Id: mxml-search.c 427 2011-01-03 02:03:29Z mike $"
3 *
4 * Search/navigation functions for Mini-XML, a small XML-like file
5 * parsing library.
6 *
7 * Copyright 2003-2010 by Michael R Sweet.
8 *
9 * These coded instructions, statements, and computer programs are the
10 * property of Michael R Sweet and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "COPYING"
12 * which should have been included with this file. If this file is
13 * missing or damaged, see the license at:
14 *
15 * http://www.minixml.org/
16 *
17 * Contents:
18 *
19 * mxmlFindElement() - Find the named element.
20 * mxmlFindValue() - Find a value with the given path.
21 * mxmlWalkNext() - Walk to the next logical node in the tree.
22 * mxmlWalkPrev() - Walk to the previous logical node in the tree.
23 */
24
25/*
26 * Include necessary headers...
27 */
28
29#include "config.h"
30#include "mxml.h"
31
32
33/*
34 * 'mxmlFindElement()' - Find the named element.
35 *
36 * The search is constrained by the name, attribute name, and value; any
37 * NULL names or values are treated as wildcards, so different kinds of
38 * searches can be implemented by looking for all elements of a given name
39 * or all elements with a specific attribute. The descend argument determines
40 * whether the search descends into child nodes; normally you will use
41 * MXML_DESCEND_FIRST for the initial search and MXML_NO_DESCEND to find
42 * additional direct descendents of the node. The top node argument
43 * constrains the search to a particular node's children.
44 */
45
46mxml_node_t * /* O - Element node or NULL */
47mxmlFindElement(mxml_node_t *node, /* I - Current node */
48 mxml_node_t *top, /* I - Top node */
49 const char *name, /* I - Element name or NULL for any */
50 const char *attr, /* I - Attribute name, or NULL for none */
51 const char *value, /* I - Attribute value, or NULL for any */
52 int descend) /* I - Descend into tree - MXML_DESCEND, MXML_NO_DESCEND, or MXML_DESCEND_FIRST */
53{
54 const char *temp; /* Current attribute value */
55
56
57 /*
58 * Range check input...
59 */
60
61 if (!node || !top || (!attr && value))
62 return (NULL);
63
64 /*
65 * Start with the next node...
66 */
67
68 node = mxmlWalkNext(node, top, descend);
69
70 /*
71 * Loop until we find a matching element...
72 */
73
74 while (node != NULL)
75 {
76 /*
77 * See if this node matches...
78 */
79
80 if (node->type == MXML_ELEMENT &&
81 node->value.element.name &&
82 (!name || !strcmp(node->value.element.name, name)))
83 {
84 /*
85 * See if we need to check for an attribute...
86 */
87
88 if (!attr)
89 return (node); /* No attribute search, return it... */
90
91 /*
92 * Check for the attribute...
93 */
94
95 if ((temp = mxmlElementGetAttr(node, attr)) != NULL)
96 {
97 /*
98 * OK, we have the attribute, does it match?
99 */
100
101 if (!value || !strcmp(value, temp))
102 return (node); /* Yes, return it... */
103 }
104 }
105
106 /*
107 * No match, move on to the next node...
108 */
109
110 if (descend == MXML_DESCEND)
111 node = mxmlWalkNext(node, top, MXML_DESCEND);
112 else
113 node = node->next;
114 }
115
116 return (NULL);
117}
118
119
120/*
121 * 'mxmlFindPath()' - Find a node with the given path.
122 *
123 * The "path" is a slash-separated list of element names. The name "*" is
124 * considered a wildcard for one or more levels of elements. For example,
125 * "foo/one/two", "bar/two/one", "*\/one", and so forth.
126 *
127 * The first child node of the found node is returned if the given node has
128 * children and the first child is a value node.
129 *
130 * @since Mini-XML 2.7@
131 */
132
133mxml_node_t * /* O - Found node or NULL */
134mxmlFindPath(mxml_node_t *top, /* I - Top node */
135 const char *path) /* I - Path to element */
136{
137 mxml_node_t *node; /* Current node */
138 char element[256]; /* Current element name */
139 const char *pathsep; /* Separator in path */
140 int descend; /* mxmlFindElement option */
141
142
143 /*
144 * Range check input...
145 */
146
147 if (!top || !path || !*path)
148 return (NULL);
149
150 /*
151 * Search each element in the path...
152 */
153
154 node = top;
155 while (*path)
156 {
157 /*
158 * Handle wildcards...
159 */
160
161 if (!strncmp(path, "*/", 2))
162 {
163 path += 2;
164 descend = MXML_DESCEND;
165 }
166 else
167 descend = MXML_DESCEND_FIRST;
168
169 /*
170 * Get the next element in the path...
171 */
172
173 if ((pathsep = strchr(path, '/')) == NULL)
174 pathsep = path + strlen(path);
175
176 if (pathsep == path || (pathsep - path) >= sizeof(element))
177 return (NULL);
178
179 memcpy(element, path, pathsep - path);
180 element[pathsep - path] = '\0';
181
182 if (*pathsep)
183 path = pathsep + 1;
184 else
185 path = pathsep;
186
187 /*
188 * Search for the element...
189 */
190
191 if ((node = mxmlFindElement(node, node, element, NULL, NULL,
192 descend)) == NULL)
193 return (NULL);
194 }
195
196 /*
197 * If we get this far, return the node or its first child...
198 */
199
200 if (node->child && node->child->type != MXML_ELEMENT)
201 return (node->child);
202 else
203 return (node);
204}
205
206
207/*
208 * 'mxmlWalkNext()' - Walk to the next logical node in the tree.
209 *
210 * The descend argument controls whether the first child is considered
211 * to be the next node. The top node argument constrains the walk to
212 * the node's children.
213 */
214
215mxml_node_t * /* O - Next node or NULL */
216mxmlWalkNext(mxml_node_t *node, /* I - Current node */
217 mxml_node_t *top, /* I - Top node */
218 int descend) /* I - Descend into tree - MXML_DESCEND, MXML_NO_DESCEND, or MXML_DESCEND_FIRST */
219{
220 if (!node)
221 return (NULL);
222 else if (node->child && descend)
223 return (node->child);
224 else if (node == top)
225 return (NULL);
226 else if (node->next)
227 return (node->next);
228 else if (node->parent && node->parent != top)
229 {
230 node = node->parent;
231
232 while (!node->next)
233 if (node->parent == top || !node->parent)
234 return (NULL);
235 else
236 node = node->parent;
237
238 return (node->next);
239 }
240 else
241 return (NULL);
242}
243
244
245/*
246 * 'mxmlWalkPrev()' - Walk to the previous logical node in the tree.
247 *
248 * The descend argument controls whether the previous node's last child
249 * is considered to be the previous node. The top node argument constrains
250 * the walk to the node's children.
251 */
252
253mxml_node_t * /* O - Previous node or NULL */
254mxmlWalkPrev(mxml_node_t *node, /* I - Current node */
255 mxml_node_t *top, /* I - Top node */
256 int descend) /* I - Descend into tree - MXML_DESCEND, MXML_NO_DESCEND, or MXML_DESCEND_FIRST */
257{
258 if (!node || node == top)
259 return (NULL);
260 else if (node->prev)
261 {
262 if (node->prev->last_child && descend)
263 {
264 /*
265 * Find the last child under the previous node...
266 */
267
268 node = node->prev->last_child;
269
270 while (node->last_child)
271 node = node->last_child;
272
273 return (node);
274 }
275 else
276 return (node->prev);
277 }
278 else if (node->parent != top)
279 return (node->parent);
280 else
281 return (NULL);
282}
283
284
285/*
286 * End of "$Id: mxml-search.c 427 2011-01-03 02:03:29Z mike $".
287 */
diff --git a/tools/gator/daemon/mxml/mxml-set.c b/tools/gator/daemon/mxml/mxml-set.c
new file mode 100644
index 00000000000..b0bd52790b2
--- /dev/null
+++ b/tools/gator/daemon/mxml/mxml-set.c
@@ -0,0 +1,349 @@
1/*
2 * "$Id: mxml-set.c 441 2011-12-09 23:49:00Z mike $"
3 *
4 * Node set functions for Mini-XML, a small XML-like file parsing library.
5 *
6 * Copyright 2003-2011 by Michael R Sweet.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Michael R Sweet and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "COPYING"
11 * which should have been included with this file. If this file is
12 * missing or damaged, see the license at:
13 *
14 * http://www.minixml.org/
15 *
16 * Contents:
17 *
18 * mxmlSetCDATA() - Set the element name of a CDATA node.
19 * mxmlSetCustom() - Set the data and destructor of a custom data node.
20 * mxmlSetElement() - Set the name of an element node.
21 * mxmlSetInteger() - Set the value of an integer node.
22 * mxmlSetOpaque() - Set the value of an opaque node.
23 * mxmlSetReal() - Set the value of a real number node.
24 * mxmlSetText() - Set the value of a text node.
25 * mxmlSetTextf() - Set the value of a text node to a formatted string.
26 * mxmlSetUserData() - Set the user data pointer for a node.
27 */
28
29/*
30 * Include necessary headers...
31 */
32
33#include "config.h"
34#include "mxml.h"
35
36
37/*
38 * 'mxmlSetCDATA()' - Set the element name of a CDATA node.
39 *
40 * The node is not changed if it (or its first child) is not a CDATA element node.
41 *
42 * @since Mini-XML 2.3@
43 */
44
45int /* O - 0 on success, -1 on failure */
46mxmlSetCDATA(mxml_node_t *node, /* I - Node to set */
47 const char *data) /* I - New data string */
48{
49 /*
50 * Range check input...
51 */
52
53 if (node && node->type == MXML_ELEMENT &&
54 strncmp(node->value.element.name, "![CDATA[", 8) &&
55 node->child && node->child->type == MXML_ELEMENT &&
56 !strncmp(node->child->value.element.name, "![CDATA[", 8))
57 node = node->child;
58
59 if (!node || node->type != MXML_ELEMENT || !data ||
60 strncmp(node->value.element.name, "![CDATA[", 8))
61 return (-1);
62
63 /*
64 * Free any old element value and set the new value...
65 */
66
67 if (node->value.element.name)
68 free(node->value.element.name);
69
70 node->value.element.name = _mxml_strdupf("![CDATA[%s]]", data);
71
72 return (0);
73}
74
75
76/*
77 * 'mxmlSetCustom()' - Set the data and destructor of a custom data node.
78 *
79 * The node is not changed if it (or its first child) is not a custom node.
80 *
81 * @since Mini-XML 2.1@
82 */
83
84int /* O - 0 on success, -1 on failure */
85mxmlSetCustom(
86 mxml_node_t *node, /* I - Node to set */
87 void *data, /* I - New data pointer */
88 mxml_custom_destroy_cb_t destroy) /* I - New destructor function */
89{
90 /*
91 * Range check input...
92 */
93
94 if (node && node->type == MXML_ELEMENT &&
95 node->child && node->child->type == MXML_CUSTOM)
96 node = node->child;
97
98 if (!node || node->type != MXML_CUSTOM)
99 return (-1);
100
101 /*
102 * Free any old element value and set the new value...
103 */
104
105 if (node->value.custom.data && node->value.custom.destroy)
106 (*(node->value.custom.destroy))(node->value.custom.data);
107
108 node->value.custom.data = data;
109 node->value.custom.destroy = destroy;
110
111 return (0);
112}
113
114
115/*
116 * 'mxmlSetElement()' - Set the name of an element node.
117 *
118 * The node is not changed if it is not an element node.
119 */
120
121int /* O - 0 on success, -1 on failure */
122mxmlSetElement(mxml_node_t *node, /* I - Node to set */
123 const char *name) /* I - New name string */
124{
125 /*
126 * Range check input...
127 */
128
129 if (!node || node->type != MXML_ELEMENT || !name)
130 return (-1);
131
132 /*
133 * Free any old element value and set the new value...
134 */
135
136 if (node->value.element.name)
137 free(node->value.element.name);
138
139 node->value.element.name = strdup(name);
140
141 return (0);
142}
143
144
145/*
146 * 'mxmlSetInteger()' - Set the value of an integer node.
147 *
148 * The node is not changed if it (or its first child) is not an integer node.
149 */
150
151int /* O - 0 on success, -1 on failure */
152mxmlSetInteger(mxml_node_t *node, /* I - Node to set */
153 int integer) /* I - Integer value */
154{
155 /*
156 * Range check input...
157 */
158
159 if (node && node->type == MXML_ELEMENT &&
160 node->child && node->child->type == MXML_INTEGER)
161 node = node->child;
162
163 if (!node || node->type != MXML_INTEGER)
164 return (-1);
165
166 /*
167 * Set the new value and return...
168 */
169
170 node->value.integer = integer;
171
172 return (0);
173}
174
175
176/*
177 * 'mxmlSetOpaque()' - Set the value of an opaque node.
178 *
179 * The node is not changed if it (or its first child) is not an opaque node.
180 */
181
182int /* O - 0 on success, -1 on failure */
183mxmlSetOpaque(mxml_node_t *node, /* I - Node to set */
184 const char *opaque) /* I - Opaque string */
185{
186 /*
187 * Range check input...
188 */
189
190 if (node && node->type == MXML_ELEMENT &&
191 node->child && node->child->type == MXML_OPAQUE)
192 node = node->child;
193
194 if (!node || node->type != MXML_OPAQUE || !opaque)
195 return (-1);
196
197 /*
198 * Free any old opaque value and set the new value...
199 */
200
201 if (node->value.opaque)
202 free(node->value.opaque);
203
204 node->value.opaque = strdup(opaque);
205
206 return (0);
207}
208
209
210/*
211 * 'mxmlSetReal()' - Set the value of a real number node.
212 *
213 * The node is not changed if it (or its first child) is not a real number node.
214 */
215
216int /* O - 0 on success, -1 on failure */
217mxmlSetReal(mxml_node_t *node, /* I - Node to set */
218 double real) /* I - Real number value */
219{
220 /*
221 * Range check input...
222 */
223
224 if (node && node->type == MXML_ELEMENT &&
225 node->child && node->child->type == MXML_REAL)
226 node = node->child;
227
228 if (!node || node->type != MXML_REAL)
229 return (-1);
230
231 /*
232 * Set the new value and return...
233 */
234
235 node->value.real = real;
236
237 return (0);
238}
239
240
241/*
242 * 'mxmlSetText()' - Set the value of a text node.
243 *
244 * The node is not changed if it (or its first child) is not a text node.
245 */
246
247int /* O - 0 on success, -1 on failure */
248mxmlSetText(mxml_node_t *node, /* I - Node to set */
249 int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */
250 const char *string) /* I - String */
251{
252 /*
253 * Range check input...
254 */
255
256 if (node && node->type == MXML_ELEMENT &&
257 node->child && node->child->type == MXML_TEXT)
258 node = node->child;
259
260 if (!node || node->type != MXML_TEXT || !string)
261 return (-1);
262
263 /*
264 * Free any old string value and set the new value...
265 */
266
267 if (node->value.text.string)
268 free(node->value.text.string);
269
270 node->value.text.whitespace = whitespace;
271 node->value.text.string = strdup(string);
272
273 return (0);
274}
275
276
277/*
278 * 'mxmlSetTextf()' - Set the value of a text node to a formatted string.
279 *
280 * The node is not changed if it (or its first child) is not a text node.
281 */
282
283int /* O - 0 on success, -1 on failure */
284mxmlSetTextf(mxml_node_t *node, /* I - Node to set */
285 int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */
286 const char *format, /* I - Printf-style format string */
287 ...) /* I - Additional arguments as needed */
288{
289 va_list ap; /* Pointer to arguments */
290
291
292 /*
293 * Range check input...
294 */
295
296 if (node && node->type == MXML_ELEMENT &&
297 node->child && node->child->type == MXML_TEXT)
298 node = node->child;
299
300 if (!node || node->type != MXML_TEXT || !format)
301 return (-1);
302
303 /*
304 * Free any old string value and set the new value...
305 */
306
307 if (node->value.text.string)
308 free(node->value.text.string);
309
310 va_start(ap, format);
311
312 node->value.text.whitespace = whitespace;
313 node->value.text.string = _mxml_strdupf(format, ap);
314
315 va_end(ap);
316
317 return (0);
318}
319
320
321/*
322 * 'mxmlSetUserData()' - Set the user data pointer for a node.
323 *
324 * @since Mini-XML 2.7@
325 */
326
327int /* O - 0 on success, -1 on failure */
328mxmlSetUserData(mxml_node_t *node, /* I - Node to set */
329 void *data) /* I - User data pointer */
330{
331 /*
332 * Range check input...
333 */
334
335 if (!node)
336 return (-1);
337
338 /*
339 * Set the user data pointer and return...
340 */
341
342 node->user_data = data;
343 return (0);
344}
345
346
347/*
348 * End of "$Id: mxml-set.c 441 2011-12-09 23:49:00Z mike $".
349 */
diff --git a/tools/gator/daemon/mxml/mxml-string.c b/tools/gator/daemon/mxml/mxml-string.c
new file mode 100644
index 00000000000..6be42523f95
--- /dev/null
+++ b/tools/gator/daemon/mxml/mxml-string.c
@@ -0,0 +1,476 @@
1/*
2 * "$Id: mxml-string.c 424 2010-12-25 16:21:50Z mike $"
3 *
4 * String functions for Mini-XML, a small XML-like file parsing library.
5 *
6 * Copyright 2003-2010 by Michael R Sweet.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Michael R Sweet and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "COPYING"
11 * which should have been included with this file. If this file is
12 * missing or damaged, see the license at:
13 *
14 * http://www.minixml.org/
15 *
16 * Contents:
17 *
18 * _mxml_snprintf() - Format a string.
19 * _mxml_strdup() - Duplicate a string.
20 * _mxml_strdupf() - Format and duplicate a string.
21 * _mxml_vsnprintf() - Format a string into a fixed size buffer.
22 * _mxml_vstrdupf() - Format and duplicate a string.
23 */
24
25/*
26 * Include necessary headers...
27 */
28
29#include "config.h"
30
31
32/*
33 * The va_copy macro is part of C99, but many compilers don't implement it.
34 * Provide a "direct assignment" implmentation when va_copy isn't defined...
35 */
36
37#ifndef va_copy
38# ifdef __va_copy
39# define va_copy(dst,src) __va_copy(dst,src)
40# else
41# define va_copy(dst,src) memcpy(&dst, &src, sizeof(va_list))
42# endif /* __va_copy */
43#endif /* va_copy */
44
45
46#ifndef HAVE_SNPRINTF
47/*
48 * '_mxml_snprintf()' - Format a string.
49 */
50
51int /* O - Number of bytes formatted */
52_mxml_snprintf(char *buffer, /* I - Output buffer */
53 size_t bufsize, /* I - Size of output buffer */
54 const char *format, /* I - Printf-style format string */
55 ...) /* I - Additional arguments as needed */
56{
57 va_list ap; /* Argument list */
58 int bytes; /* Number of bytes formatted */
59
60
61 va_start(ap, format);
62 bytes = vsnprintf(buffer, bufsize, format, ap);
63 va_end(ap);
64
65 return (bytes);
66}
67#endif /* !HAVE_SNPRINTF */
68
69
70/*
71 * '_mxml_strdup()' - Duplicate a string.
72 */
73
74#ifndef HAVE_STRDUP
75char * /* O - New string pointer */
76_mxml_strdup(const char *s) /* I - String to duplicate */
77{
78 char *t; /* New string pointer */
79
80
81 if (s == NULL)
82 return (NULL);
83
84 if ((t = malloc(strlen(s) + 1)) == NULL)
85 return (NULL);
86
87 return (strcpy(t, s));
88}
89#endif /* !HAVE_STRDUP */
90
91
92/*
93 * '_mxml_strdupf()' - Format and duplicate a string.
94 */
95
96char * /* O - New string pointer */
97_mxml_strdupf(const char *format, /* I - Printf-style format string */
98 ...) /* I - Additional arguments as needed */
99{
100 va_list ap; /* Pointer to additional arguments */
101 char *s; /* Pointer to formatted string */
102
103
104 /*
105 * Get a pointer to the additional arguments, format the string,
106 * and return it...
107 */
108
109 va_start(ap, format);
110 s = _mxml_vstrdupf(format, ap);
111 va_end(ap);
112
113 return (s);
114}
115
116
117#ifndef HAVE_VSNPRINTF
118/*
119 * '_mxml_vsnprintf()' - Format a string into a fixed size buffer.
120 */
121
122int /* O - Number of bytes formatted */
123_mxml_vsnprintf(char *buffer, /* O - Output buffer */
124 size_t bufsize, /* O - Size of output buffer */
125 const char *format, /* I - Printf-style format string */
126 va_list ap) /* I - Pointer to additional arguments */
127{
128 char *bufptr, /* Pointer to position in buffer */
129 *bufend, /* Pointer to end of buffer */
130 sign, /* Sign of format width */
131 size, /* Size character (h, l, L) */
132 type; /* Format type character */
133 int width, /* Width of field */
134 prec; /* Number of characters of precision */
135 char tformat[100], /* Temporary format string for sprintf() */
136 *tptr, /* Pointer into temporary format */
137 temp[1024]; /* Buffer for formatted numbers */
138 char *s; /* Pointer to string */
139 int slen; /* Length of string */
140 int bytes; /* Total number of bytes needed */
141
142
143 /*
144 * Loop through the format string, formatting as needed...
145 */
146
147 bufptr = buffer;
148 bufend = buffer + bufsize - 1;
149 bytes = 0;
150
151 while (*format)
152 {
153 if (*format == '%')
154 {
155 tptr = tformat;
156 *tptr++ = *format++;
157
158 if (*format == '%')
159 {
160 if (bufptr && bufptr < bufend) *bufptr++ = *format;
161 bytes ++;
162 format ++;
163 continue;
164 }
165 else if (strchr(" -+#\'", *format))
166 {
167 *tptr++ = *format;
168 sign = *format++;
169 }
170 else
171 sign = 0;
172
173 if (*format == '*')
174 {
175 /*
176 * Get width from argument...
177 */
178
179 format ++;
180 width = va_arg(ap, int);
181
182 snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", width);
183 tptr += strlen(tptr);
184 }
185 else
186 {
187 width = 0;
188
189 while (isdigit(*format & 255))
190 {
191 if (tptr < (tformat + sizeof(tformat) - 1))
192 *tptr++ = *format;
193
194 width = width * 10 + *format++ - '0';
195 }
196 }
197
198 if (*format == '.')
199 {
200 if (tptr < (tformat + sizeof(tformat) - 1))
201 *tptr++ = *format;
202
203 format ++;
204
205 if (*format == '*')
206 {
207 /*
208 * Get precision from argument...
209 */
210
211 format ++;
212 prec = va_arg(ap, int);
213
214 snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", prec);
215 tptr += strlen(tptr);
216 }
217 else
218 {
219 prec = 0;
220
221 while (isdigit(*format & 255))
222 {
223 if (tptr < (tformat + sizeof(tformat) - 1))
224 *tptr++ = *format;
225
226 prec = prec * 10 + *format++ - '0';
227 }
228 }
229 }
230 else
231 prec = -1;
232
233 if (*format == 'l' && format[1] == 'l')
234 {
235 size = 'L';
236
237 if (tptr < (tformat + sizeof(tformat) - 2))
238 {
239 *tptr++ = 'l';
240 *tptr++ = 'l';
241 }
242
243 format += 2;
244 }
245 else if (*format == 'h' || *format == 'l' || *format == 'L')
246 {
247 if (tptr < (tformat + sizeof(tformat) - 1))
248 *tptr++ = *format;
249
250 size = *format++;
251 }
252
253 if (!*format)
254 break;
255
256 if (tptr < (tformat + sizeof(tformat) - 1))
257 *tptr++ = *format;
258
259 type = *format++;
260 *tptr = '\0';
261
262 switch (type)
263 {
264 case 'E' : /* Floating point formats */
265 case 'G' :
266 case 'e' :
267 case 'f' :
268 case 'g' :
269 if ((width + 2) > sizeof(temp))
270 break;
271
272 sprintf(temp, tformat, va_arg(ap, double));
273
274 bytes += strlen(temp);
275
276 if (bufptr)
277 {
278 if ((bufptr + strlen(temp)) > bufend)
279 {
280 strncpy(bufptr, temp, (size_t)(bufend - bufptr));
281 bufptr = bufend;
282 }
283 else
284 {
285 strcpy(bufptr, temp);
286 bufptr += strlen(temp);
287 }
288 }
289 break;
290
291 case 'B' : /* Integer formats */
292 case 'X' :
293 case 'b' :
294 case 'd' :
295 case 'i' :
296 case 'o' :
297 case 'u' :
298 case 'x' :
299 if ((width + 2) > sizeof(temp))
300 break;
301
302#ifdef HAVE_LONG_LONG
303 if (size == 'L')
304 sprintf(temp, tformat, va_arg(ap, long long));
305 else
306#endif /* HAVE_LONG_LONG */
307 sprintf(temp, tformat, va_arg(ap, int));
308
309 bytes += strlen(temp);
310
311 if (bufptr)
312 {
313 if ((bufptr + strlen(temp)) > bufend)
314 {
315 strncpy(bufptr, temp, (size_t)(bufend - bufptr));
316 bufptr = bufend;
317 }
318 else
319 {
320 strcpy(bufptr, temp);
321 bufptr += strlen(temp);
322 }
323 }
324 break;
325
326 case 'p' : /* Pointer value */
327 if ((width + 2) > sizeof(temp))
328 break;
329
330 sprintf(temp, tformat, va_arg(ap, void *));
331
332 bytes += strlen(temp);
333
334 if (bufptr)
335 {
336 if ((bufptr + strlen(temp)) > bufend)
337 {
338 strncpy(bufptr, temp, (size_t)(bufend - bufptr));
339 bufptr = bufend;
340 }
341 else
342 {
343 strcpy(bufptr, temp);
344 bufptr += strlen(temp);
345 }
346 }
347 break;
348
349 case 'c' : /* Character or character array */
350 bytes += width;
351
352 if (bufptr)
353 {
354 if (width <= 1)
355 *bufptr++ = va_arg(ap, int);
356 else
357 {
358 if ((bufptr + width) > bufend)
359 width = bufend - bufptr;
360
361 memcpy(bufptr, va_arg(ap, char *), (size_t)width);
362 bufptr += width;
363 }
364 }
365 break;
366
367 case 's' : /* String */
368 if ((s = va_arg(ap, char *)) == NULL)
369 s = "(null)";
370
371 slen = strlen(s);
372 if (slen > width && prec != width)
373 width = slen;
374
375 bytes += width;
376
377 if (bufptr)
378 {
379 if ((bufptr + width) > bufend)
380 width = bufend - bufptr;
381
382 if (slen > width)
383 slen = width;
384
385 if (sign == '-')
386 {
387 strncpy(bufptr, s, (size_t)slen);
388 memset(bufptr + slen, ' ', (size_t)(width - slen));
389 }
390 else
391 {
392 memset(bufptr, ' ', (size_t)(width - slen));
393 strncpy(bufptr + width - slen, s, (size_t)slen);
394 }
395
396 bufptr += width;
397 }
398 break;
399
400 case 'n' : /* Output number of chars so far */
401 *(va_arg(ap, int *)) = bytes;
402 break;
403 }
404 }
405 else
406 {
407 bytes ++;
408
409 if (bufptr && bufptr < bufend)
410 *bufptr++ = *format;
411
412 format ++;
413 }
414 }
415
416 /*
417 * Nul-terminate the string and return the number of characters needed.
418 */
419
420 *bufptr = '\0';
421
422 return (bytes);
423}
424#endif /* !HAVE_VSNPRINTF */
425
426
427/*
428 * '_mxml_vstrdupf()' - Format and duplicate a string.
429 */
430
431char * /* O - New string pointer */
432_mxml_vstrdupf(const char *format, /* I - Printf-style format string */
433 va_list ap) /* I - Pointer to additional arguments */
434{
435 int bytes; /* Number of bytes required */
436 char *buffer, /* String buffer */
437 temp[256]; /* Small buffer for first vsnprintf */
438 va_list apcopy; /* Copy of argument list */
439
440
441 /*
442 * First format with a tiny buffer; this will tell us how many bytes are
443 * needed...
444 */
445
446 va_copy(apcopy, ap);
447 bytes = vsnprintf(temp, sizeof(temp), format, apcopy);
448
449 if (bytes < sizeof(temp))
450 {
451 /*
452 * Hey, the formatted string fits in the tiny buffer, so just dup that...
453 */
454
455 return (strdup(temp));
456 }
457
458 /*
459 * Allocate memory for the whole thing and reformat to the new, larger
460 * buffer...
461 */
462
463 if ((buffer = calloc(1, bytes + 1)) != NULL)
464 vsnprintf(buffer, bytes + 1, format, ap);
465
466 /*
467 * Return the new string...
468 */
469
470 return (buffer);
471}
472
473
474/*
475 * End of "$Id: mxml-string.c 424 2010-12-25 16:21:50Z mike $".
476 */
diff --git a/tools/gator/daemon/mxml/mxml.h b/tools/gator/daemon/mxml/mxml.h
new file mode 100644
index 00000000000..79c711f4c80
--- /dev/null
+++ b/tools/gator/daemon/mxml/mxml.h
@@ -0,0 +1,329 @@
1/*
2 * "$Id: mxml.h 427 2011-01-03 02:03:29Z mike $"
3 *
4 * Header file for Mini-XML, a small XML-like file parsing library.
5 *
6 * Copyright 2003-2011 by Michael R Sweet.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Michael R Sweet and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "COPYING"
11 * which should have been included with this file. If this file is
12 * missing or damaged, see the license at:
13 *
14 * http://www.minixml.org/
15 */
16
17/*
18 * Prevent multiple inclusion...
19 */
20
21#ifndef _mxml_h_
22# define _mxml_h_
23
24/*
25 * Include necessary headers...
26 */
27
28# include <stdio.h>
29# include <stdlib.h>
30# include <string.h>
31# include <ctype.h>
32# include <errno.h>
33
34
35/*
36 * Constants...
37 */
38
39# define MXML_TAB 8 /* Tabs every N columns */
40
41# define MXML_NO_CALLBACK 0 /* Don't use a type callback */
42# define MXML_INTEGER_CALLBACK mxml_integer_cb
43 /* Treat all data as integers */
44# define MXML_OPAQUE_CALLBACK mxml_opaque_cb
45 /* Treat all data as opaque */
46# define MXML_REAL_CALLBACK mxml_real_cb
47 /* Treat all data as real numbers */
48# define MXML_TEXT_CALLBACK 0 /* Treat all data as text */
49# define MXML_IGNORE_CALLBACK mxml_ignore_cb
50 /* Ignore all non-element content */
51
52# define MXML_NO_PARENT 0 /* No parent for the node */
53
54# define MXML_DESCEND 1 /* Descend when finding/walking */
55# define MXML_NO_DESCEND 0 /* Don't descend when finding/walking */
56# define MXML_DESCEND_FIRST -1 /* Descend for first find */
57
58# define MXML_WS_BEFORE_OPEN 0 /* Callback for before open tag */
59# define MXML_WS_AFTER_OPEN 1 /* Callback for after open tag */
60# define MXML_WS_BEFORE_CLOSE 2 /* Callback for before close tag */
61# define MXML_WS_AFTER_CLOSE 3 /* Callback for after close tag */
62
63# define MXML_ADD_BEFORE 0 /* Add node before specified node */
64# define MXML_ADD_AFTER 1 /* Add node after specified node */
65# define MXML_ADD_TO_PARENT NULL /* Add node relative to parent */
66
67
68/*
69 * Data types...
70 */
71
72typedef enum mxml_sax_event_e /**** SAX event type. ****/
73{
74 MXML_SAX_CDATA, /* CDATA node */
75 MXML_SAX_COMMENT, /* Comment node */
76 MXML_SAX_DATA, /* Data node */
77 MXML_SAX_DIRECTIVE, /* Processing directive node */
78 MXML_SAX_ELEMENT_CLOSE, /* Element closed */
79 MXML_SAX_ELEMENT_OPEN /* Element opened */
80} mxml_sax_event_t;
81
82typedef enum mxml_type_e /**** The XML node type. ****/
83{
84 MXML_IGNORE = -1, /* Ignore/throw away node @since Mini-XML 2.3@ */
85 MXML_ELEMENT, /* XML element with attributes */
86 MXML_INTEGER, /* Integer value */
87 MXML_OPAQUE, /* Opaque string */
88 MXML_REAL, /* Real value */
89 MXML_TEXT, /* Text fragment */
90 MXML_CUSTOM /* Custom data @since Mini-XML 2.1@ */
91} mxml_type_t;
92
93typedef void (*mxml_custom_destroy_cb_t)(void *);
94 /**** Custom data destructor ****/
95
96typedef void (*mxml_error_cb_t)(const char *);
97 /**** Error callback function ****/
98
99typedef struct mxml_attr_s /**** An XML element attribute value. @private@ ****/
100{
101 char *name; /* Attribute name */
102 char *value; /* Attribute value */
103} mxml_attr_t;
104
105typedef struct mxml_element_s /**** An XML element value. @private@ ****/
106{
107 char *name; /* Name of element */
108 int num_attrs; /* Number of attributes */
109 mxml_attr_t *attrs; /* Attributes */
110} mxml_element_t;
111
112typedef struct mxml_text_s /**** An XML text value. @private@ ****/
113{
114 int whitespace; /* Leading whitespace? */
115 char *string; /* Fragment string */
116} mxml_text_t;
117
118typedef struct mxml_custom_s /**** An XML custom value. @private@ ****/
119{
120 void *data; /* Pointer to (allocated) custom data */
121 mxml_custom_destroy_cb_t destroy; /* Pointer to destructor function */
122} mxml_custom_t;
123
124typedef union mxml_value_u /**** An XML node value. @private@ ****/
125{
126 mxml_element_t element; /* Element */
127 int integer; /* Integer number */
128 char *opaque; /* Opaque string */
129 double real; /* Real number */
130 mxml_text_t text; /* Text fragment */
131 mxml_custom_t custom; /* Custom data @since Mini-XML 2.1@ */
132} mxml_value_t;
133
134struct mxml_node_s /**** An XML node. @private@ ****/
135{
136 mxml_type_t type; /* Node type */
137 struct mxml_node_s *next; /* Next node under same parent */
138 struct mxml_node_s *prev; /* Previous node under same parent */
139 struct mxml_node_s *parent; /* Parent node */
140 struct mxml_node_s *child; /* First child node */
141 struct mxml_node_s *last_child; /* Last child node */
142 mxml_value_t value; /* Node value */
143 int ref_count; /* Use count */
144 void *user_data; /* User data */
145};
146
147typedef struct mxml_node_s mxml_node_t; /**** An XML node. ****/
148
149struct mxml_index_s /**** An XML node index. @private@ ****/
150{
151 char *attr; /* Attribute used for indexing or NULL */
152 int num_nodes; /* Number of nodes in index */
153 int alloc_nodes; /* Allocated nodes in index */
154 int cur_node; /* Current node */
155 mxml_node_t **nodes; /* Node array */
156};
157
158typedef struct mxml_index_s mxml_index_t;
159 /**** An XML node index. ****/
160
161typedef int (*mxml_custom_load_cb_t)(mxml_node_t *, const char *);
162 /**** Custom data load callback function ****/
163
164typedef char *(*mxml_custom_save_cb_t)(mxml_node_t *);
165 /**** Custom data save callback function ****/
166
167typedef int (*mxml_entity_cb_t)(const char *);
168 /**** Entity callback function */
169
170typedef mxml_type_t (*mxml_load_cb_t)(mxml_node_t *);
171 /**** Load callback function ****/
172
173typedef const char *(*mxml_save_cb_t)(mxml_node_t *, int);
174 /**** Save callback function ****/
175
176typedef void (*mxml_sax_cb_t)(mxml_node_t *, mxml_sax_event_t, void *);
177 /**** SAX callback function ****/
178
179
180/*
181 * C++ support...
182 */
183
184# ifdef __cplusplus
185extern "C" {
186# endif /* __cplusplus */
187
188/*
189 * Prototypes...
190 */
191
192extern void mxmlAdd(mxml_node_t *parent, int where,
193 mxml_node_t *child, mxml_node_t *node);
194extern void mxmlDelete(mxml_node_t *node);
195extern void mxmlElementDeleteAttr(mxml_node_t *node,
196 const char *name);
197extern const char *mxmlElementGetAttr(mxml_node_t *node, const char *name);
198extern void mxmlElementSetAttr(mxml_node_t *node, const char *name,
199 const char *value);
200extern void mxmlElementSetAttrf(mxml_node_t *node, const char *name,
201 const char *format, ...)
202# ifdef __GNUC__
203__attribute__ ((__format__ (__printf__, 3, 4)))
204# endif /* __GNUC__ */
205;
206extern int mxmlEntityAddCallback(mxml_entity_cb_t cb);
207extern const char *mxmlEntityGetName(int val);
208extern int mxmlEntityGetValue(const char *name);
209extern void mxmlEntityRemoveCallback(mxml_entity_cb_t cb);
210extern mxml_node_t *mxmlFindElement(mxml_node_t *node, mxml_node_t *top,
211 const char *name, const char *attr,
212 const char *value, int descend);
213extern mxml_node_t *mxmlFindPath(mxml_node_t *node, const char *path);
214extern const char *mxmlGetCDATA(mxml_node_t *node);
215extern const void *mxmlGetCustom(mxml_node_t *node);
216extern const char *mxmlGetElement(mxml_node_t *node);
217extern mxml_node_t *mxmlGetFirstChild(mxml_node_t *node);
218extern int mxmlGetInteger(mxml_node_t *node);
219extern mxml_node_t *mxmlGetLastChild(mxml_node_t *node);
220extern mxml_node_t *mxmlGetNextSibling(mxml_node_t *node);
221extern const char *mxmlGetOpaque(mxml_node_t *node);
222extern mxml_node_t *mxmlGetParent(mxml_node_t *node);
223extern mxml_node_t *mxmlGetPrevSibling(mxml_node_t *node);
224extern double mxmlGetReal(mxml_node_t *node);
225extern int mxmlGetRefCount(mxml_node_t *node);
226extern const char *mxmlGetText(mxml_node_t *node, int *whitespace);
227extern mxml_type_t mxmlGetType(mxml_node_t *node);
228extern void *mxmlGetUserData(mxml_node_t *node);
229extern void mxmlIndexDelete(mxml_index_t *ind);
230extern mxml_node_t *mxmlIndexEnum(mxml_index_t *ind);
231extern mxml_node_t *mxmlIndexFind(mxml_index_t *ind,
232 const char *element,
233 const char *value);
234extern int mxmlIndexGetCount(mxml_index_t *ind);
235extern mxml_index_t *mxmlIndexNew(mxml_node_t *node, const char *element,
236 const char *attr);
237extern mxml_node_t *mxmlIndexReset(mxml_index_t *ind);
238extern mxml_node_t *mxmlLoadFd(mxml_node_t *top, int fd,
239 mxml_type_t (*cb)(mxml_node_t *));
240extern mxml_node_t *mxmlLoadFile(mxml_node_t *top, FILE *fp,
241 mxml_type_t (*cb)(mxml_node_t *));
242extern mxml_node_t *mxmlLoadString(mxml_node_t *top, const char *s,
243 mxml_type_t (*cb)(mxml_node_t *));
244extern mxml_node_t *mxmlNewCDATA(mxml_node_t *parent, const char *string);
245extern mxml_node_t *mxmlNewCustom(mxml_node_t *parent, void *data,
246 mxml_custom_destroy_cb_t destroy);
247extern mxml_node_t *mxmlNewElement(mxml_node_t *parent, const char *name);
248extern mxml_node_t *mxmlNewInteger(mxml_node_t *parent, int integer);
249extern mxml_node_t *mxmlNewOpaque(mxml_node_t *parent, const char *opaque);
250extern mxml_node_t *mxmlNewReal(mxml_node_t *parent, double real);
251extern mxml_node_t *mxmlNewText(mxml_node_t *parent, int whitespace,
252 const char *string);
253extern mxml_node_t *mxmlNewTextf(mxml_node_t *parent, int whitespace,
254 const char *format, ...)
255# ifdef __GNUC__
256__attribute__ ((__format__ (__printf__, 3, 4)))
257# endif /* __GNUC__ */
258;
259extern mxml_node_t *mxmlNewXML(const char *version);
260extern int mxmlRelease(mxml_node_t *node);
261extern void mxmlRemove(mxml_node_t *node);
262extern int mxmlRetain(mxml_node_t *node);
263extern char *mxmlSaveAllocString(mxml_node_t *node,
264 mxml_save_cb_t cb);
265extern int mxmlSaveFd(mxml_node_t *node, int fd,
266 mxml_save_cb_t cb);
267extern int mxmlSaveFile(mxml_node_t *node, FILE *fp,
268 mxml_save_cb_t cb);
269extern int mxmlSaveString(mxml_node_t *node, char *buffer,
270 int bufsize, mxml_save_cb_t cb);
271extern mxml_node_t *mxmlSAXLoadFd(mxml_node_t *top, int fd,
272 mxml_type_t (*cb)(mxml_node_t *),
273 mxml_sax_cb_t sax, void *sax_data);
274extern mxml_node_t *mxmlSAXLoadFile(mxml_node_t *top, FILE *fp,
275 mxml_type_t (*cb)(mxml_node_t *),
276 mxml_sax_cb_t sax, void *sax_data);
277extern mxml_node_t *mxmlSAXLoadString(mxml_node_t *top, const char *s,
278 mxml_type_t (*cb)(mxml_node_t *),
279 mxml_sax_cb_t sax, void *sax_data);
280extern int mxmlSetCDATA(mxml_node_t *node, const char *data);
281extern int mxmlSetCustom(mxml_node_t *node, void *data,
282 mxml_custom_destroy_cb_t destroy);
283extern void mxmlSetCustomHandlers(mxml_custom_load_cb_t load,
284 mxml_custom_save_cb_t save);
285extern int mxmlSetElement(mxml_node_t *node, const char *name);
286extern void mxmlSetErrorCallback(mxml_error_cb_t cb);
287extern int mxmlSetInteger(mxml_node_t *node, int integer);
288extern int mxmlSetOpaque(mxml_node_t *node, const char *opaque);
289extern int mxmlSetReal(mxml_node_t *node, double real);
290extern int mxmlSetText(mxml_node_t *node, int whitespace,
291 const char *string);
292extern int mxmlSetTextf(mxml_node_t *node, int whitespace,
293 const char *format, ...)
294# ifdef __GNUC__
295__attribute__ ((__format__ (__printf__, 3, 4)))
296# endif /* __GNUC__ */
297;
298extern int mxmlSetUserData(mxml_node_t *node, void *data);
299extern void mxmlSetWrapMargin(int column);
300extern mxml_node_t *mxmlWalkNext(mxml_node_t *node, mxml_node_t *top,
301 int descend);
302extern mxml_node_t *mxmlWalkPrev(mxml_node_t *node, mxml_node_t *top,
303 int descend);
304
305
306/*
307 * Semi-private functions...
308 */
309
310extern void mxml_error(const char *format, ...);
311extern mxml_type_t mxml_ignore_cb(mxml_node_t *node);
312extern mxml_type_t mxml_integer_cb(mxml_node_t *node);
313extern mxml_type_t mxml_opaque_cb(mxml_node_t *node);
314extern mxml_type_t mxml_real_cb(mxml_node_t *node);
315
316
317/*
318 * C++ support...
319 */
320
321# ifdef __cplusplus
322}
323# endif /* __cplusplus */
324#endif /* !_mxml_h_ */
325
326
327/*
328 * End of "$Id: mxml.h 427 2011-01-03 02:03:29Z mike $".
329 */