From: Jon Medhurst Date: Fri, 8 May 2015 11:04:18 +0000 (+0100) Subject: gator: Version 5.21.1 X-Git-Tag: firefly_0821_release~3680^2~7^2~2^2^2^2~2 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=b1d07441d04e4116638a1fc162cb7c6e55b2915a;p=firefly-linux-kernel-4.4.55.git gator: Version 5.21.1 Signed-off-by: Drew Richardson Signed-off-by: Jon Medhurst --- diff --git a/drivers/gator/COPYING b/drivers/gator/COPYING new file mode 100644 index 000000000000..d159169d1050 --- /dev/null +++ b/drivers/gator/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/drivers/gator/LICENSE b/drivers/gator/LICENSE deleted file mode 100644 index d159169d1050..000000000000 --- a/drivers/gator/LICENSE +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/drivers/gator/Makefile b/drivers/gator/Makefile index 28d2070b11d5..d14e2a02fee0 100644 --- a/drivers/gator/Makefile +++ b/drivers/gator/Makefile @@ -63,6 +63,22 @@ gator-$(CONFIG_ARM) += gator_events_armv6.o \ gator-$(CONFIG_ARM64) += +$(obj)/gator_main.o: $(obj)/gator_src_md5.h + +clean-files := gator_src_md5.h + +# Note, in the recipe below we use "cd $(srctree) && cd $(src)" rather than +# "cd $(srctree)/$(src)" because under DKMS $(src) is an absolute path, and we +# can't just use $(src) because for normal kernel builds this is relative to +# $(srctree) + + chk_events.h = : + quiet_chk_events.h = echo ' CHK $@' +silent_chk_events.h = : +$(obj)/gator_src_md5.h: FORCE + @$($(quiet)chk_events.h) + $(Q)cd $(srctree) && cd $(src) ; $(CONFIG_SHELL) -c "echo 'static char *gator_src_md5 = \"'\`ls *.c *.h mali/*.h | grep -Ev '^(gator_src_md5\.c|gator\.mod\.c)$$' | LC_ALL=C sort | xargs cat | md5sum | cut -b 1-32\`'\";'" > $(abspath $@) + else all: @@ -73,7 +89,7 @@ all: $(error) clean: - rm -f *.o .*.cmd modules.order Module.symvers gator.ko gator.mod.c + rm -f *.o .*.cmd gator_src_md5.h modules.order Module.symvers gator.ko gator.mod.c rm -rf .tmp_versions endif diff --git a/drivers/gator/gator.h b/drivers/gator/gator.h index 5cc73a388c4f..202eb41c485b 100644 --- a/drivers/gator/gator.h +++ b/drivers/gator/gator.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -21,25 +21,26 @@ #define GATOR_IKS_SUPPORT defined(CONFIG_BL_SWITCHER) /* cpu ids */ -#define ARM1136 0xb36 -#define ARM1156 0xb56 -#define ARM1176 0xb76 -#define ARM11MPCORE 0xb02 -#define CORTEX_A5 0xc05 -#define CORTEX_A7 0xc07 -#define CORTEX_A8 0xc08 -#define CORTEX_A9 0xc09 -#define CORTEX_A15 0xc0f -#define CORTEX_A17 0xc0e -#define SCORPION 0x00f -#define SCORPIONMP 0x02d -#define KRAITSIM 0x049 -#define KRAIT 0x04d -#define KRAIT_S4_PRO 0x06f -#define CORTEX_A53 0xd03 -#define CORTEX_A57 0xd07 -#define AARCH64 0xd0f -#define OTHER 0xfff +#define ARM1136 0x41b36 +#define ARM1156 0x41b56 +#define ARM1176 0x41b76 +#define ARM11MPCORE 0x41b02 +#define CORTEX_A5 0x41c05 +#define CORTEX_A7 0x41c07 +#define CORTEX_A8 0x41c08 +#define CORTEX_A9 0x41c09 +#define CORTEX_A15 0x41c0f +#define CORTEX_A12 0x41c0d +#define CORTEX_A17 0x41c0e +#define SCORPION 0x5100f +#define SCORPIONMP 0x5102d +#define KRAITSIM 0x51049 +#define KRAIT 0x5104d +#define KRAIT_S4_PRO 0x5106f +#define CORTEX_A53 0x41d03 +#define CORTEX_A57 0x41d07 +#define CORTEX_A72 0x41d08 +#define OTHER 0xfffff /* gpu enums */ #define MALI_4xx 1 diff --git a/drivers/gator/gator_annotate.c b/drivers/gator/gator_annotate.c index ff9a3cef7b2e..cc9ae02e5fba 100644 --- a/drivers/gator/gator_annotate.c +++ b/drivers/gator/gator_annotate.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/gator/gator_annotate_kernel.c b/drivers/gator/gator_annotate_kernel.c index 69471f99e5fb..54e8e86e34cf 100644 --- a/drivers/gator/gator_annotate_kernel.c +++ b/drivers/gator/gator_annotate_kernel.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2012-2014. All rights reserved. + * Copyright (C) ARM Limited 2012-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/gator/gator_backtrace.c b/drivers/gator/gator_backtrace.c index 76c941d009a9..5557ec0b29ca 100644 --- a/drivers/gator/gator_backtrace.c +++ b/drivers/gator/gator_backtrace.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/gator/gator_buffer.c b/drivers/gator/gator_buffer.c index 910d5aa15066..f335457638ae 100644 --- a/drivers/gator/gator_buffer.c +++ b/drivers/gator/gator_buffer.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/gator/gator_buffer_write.c b/drivers/gator/gator_buffer_write.c index 654ec606cfad..b731e6a414d2 100644 --- a/drivers/gator/gator_buffer_write.c +++ b/drivers/gator/gator_buffer_write.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/gator/gator_cookies.c b/drivers/gator/gator_cookies.c index c43cce815226..9bd4c8b98c9e 100644 --- a/drivers/gator/gator_cookies.c +++ b/drivers/gator/gator_cookies.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/gator/gator_events_armv6.c b/drivers/gator/gator_events_armv6.c index a157a0013302..178397033e2c 100644 --- a/drivers/gator/gator_events_armv6.c +++ b/drivers/gator/gator_events_armv6.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/gator/gator_events_armv7.c b/drivers/gator/gator_events_armv7.c index 09c94220114c..e1f6a5fa9997 100644 --- a/drivers/gator/gator_events_armv7.c +++ b/drivers/gator/gator_events_armv7.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/gator/gator_events_block.c b/drivers/gator/gator_events_block.c index a352a54afa02..b3467b133712 100644 --- a/drivers/gator/gator_events_block.c +++ b/drivers/gator/gator_events_block.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/gator/gator_events_irq.c b/drivers/gator/gator_events_irq.c index 5221aac581b3..81b976a9b282 100644 --- a/drivers/gator/gator_events_irq.c +++ b/drivers/gator/gator_events_irq.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/gator/gator_events_l2c-310.c b/drivers/gator/gator_events_l2c-310.c index 73aaac32327e..063a06079c74 100644 --- a/drivers/gator/gator_events_l2c-310.c +++ b/drivers/gator/gator_events_l2c-310.c @@ -1,7 +1,7 @@ /** * l2c310 (L2 Cache Controller) event counters for gator * - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/gator/gator_events_mali_4xx.c b/drivers/gator/gator_events_mali_4xx.c index 9cf43fe2c29b..423b4e08e8cc 100644 --- a/drivers/gator/gator_events_mali_4xx.c +++ b/drivers/gator/gator_events_mali_4xx.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/gator/gator_events_mali_4xx.h b/drivers/gator/gator_events_mali_4xx.h index 976ca8c4cfa1..8f6a870e6d0c 100644 --- a/drivers/gator/gator_events_mali_4xx.h +++ b/drivers/gator/gator_events_mali_4xx.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2011-2014. All rights reserved. + * Copyright (C) ARM Limited 2011-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/gator/gator_events_mali_common.c b/drivers/gator/gator_events_mali_common.c index 1af87d649afe..7741f2575542 100644 --- a/drivers/gator/gator_events_mali_common.c +++ b/drivers/gator/gator_events_mali_common.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2012-2014. All rights reserved. + * Copyright (C) ARM Limited 2012-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/gator/gator_events_mali_common.h b/drivers/gator/gator_events_mali_common.h index e7082e62fe88..a4fc9d7d4cf6 100644 --- a/drivers/gator/gator_events_mali_common.h +++ b/drivers/gator/gator_events_mali_common.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2012-2014. All rights reserved. + * Copyright (C) ARM Limited 2012-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/gator/gator_events_mali_midgard.c b/drivers/gator/gator_events_mali_midgard.c index 0aec906d7ae5..3b0963a8de21 100644 --- a/drivers/gator/gator_events_mali_midgard.c +++ b/drivers/gator/gator_events_mali_midgard.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2011-2014. All rights reserved. + * Copyright (C) ARM Limited 2011-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/gator/gator_events_mali_midgard_hw.c b/drivers/gator/gator_events_mali_midgard_hw.c index c8065da56815..7e1eee30026d 100644 --- a/drivers/gator/gator_events_mali_midgard_hw.c +++ b/drivers/gator/gator_events_mali_midgard_hw.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2012-2014. All rights reserved. + * Copyright (C) ARM Limited 2012-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -18,7 +18,7 @@ /* Mali Midgard DDK includes */ #if defined(MALI_SIMPLE_API) /* Header with wrapper functions to kbase structures and functions */ -#include "mali/mali_kbase_gator_api.h" +#include "mali_kbase_gator_api.h" #elif defined(MALI_DIR_MIDGARD) /* New DDK Directory structure with kernel/drivers/gpu/arm/midgard */ #include "mali_linux_trace.h" @@ -40,6 +40,10 @@ #error MALI_DDK_GATOR_API_VERSION is invalid (must be 1 for r1/r2 DDK, or 2 for r3/r4 DDK, or 3 for r5 and later DDK). #endif +#if !defined(CONFIG_MALI_GATOR_SUPPORT) +#error CONFIG_MALI_GATOR_SUPPORT is required for GPU activity and software counters +#endif + #include "gator_events_mali_common.h" /* @@ -748,12 +752,12 @@ static int read_counter(const int cnt, const int len, const struct mali_counter { const int block = GET_HW_BLOCK(cnt); const int counter_offset = GET_COUNTER_OFFSET(cnt); + u32 value = 0; #if MALI_DDK_GATOR_API_VERSION == 3 const char *block_base_address = (char *)in_out_info->kernel_dump_buffer; int i; int shader_core_count = 0; - u32 value = 0; for (i = 0; i < in_out_info->nr_hwc_blocks; i++) { if (block == in_out_info->hwc_layout[i]) { @@ -766,6 +770,12 @@ static int read_counter(const int cnt, const int len, const struct mali_counter if (shader_core_count > 1) value /= shader_core_count; #else + const unsigned int vithar_blocks[] = { + 0x700, /* VITHAR_JOB_MANAGER, Block 0 */ + 0x400, /* VITHAR_TILER, Block 1 */ + 0x000, /* VITHAR_SHADER_CORE, Block 2 */ + 0x500 /* VITHAR_MEMORY_SYSTEM, Block 3 */ + }; const char *block_base_address = (char *)kernel_dump_buffer + vithar_blocks[block]; /* If counter belongs to shader block need to take into account all cores */ @@ -831,31 +841,22 @@ static int read(int **buffer, bool sched_switch) * Only process hardware counters if at least one of the hardware counters is enabled. */ if (num_hardware_counters_enabled > 0) { -#if MALI_DDK_GATOR_API_VERSION != 3 - const unsigned int vithar_blocks[] = { - 0x700, /* VITHAR_JOB_MANAGER, Block 0 */ - 0x400, /* VITHAR_TILER, Block 1 */ - 0x000, /* VITHAR_SHADER_CORE, Block 2 */ - 0x500 /* VITHAR_MEMORY_SYSTEM, Block 3 */ - }; -#endif - #if MALI_DDK_GATOR_API_VERSION == 3 if (!handles) return -1; /* Mali symbols can be called safely since a kbcontext is valid */ - if (kbase_gator_instr_hwcnt_dump_complete_symbol(handles, &success) == MALI_TRUE) { + if (kbase_gator_instr_hwcnt_dump_complete_symbol(handles, &success)) { #else if (!kbcontext) return -1; /* Mali symbols can be called safely since a kbcontext is valid */ - if (kbase_instr_hwcnt_dump_complete_symbol(kbcontext, &success) == MALI_TRUE) { + if (kbase_instr_hwcnt_dump_complete_symbol(kbcontext, &success)) { #endif kbase_device_busy = false; - if (success == MALI_TRUE) { + if (success) { /* Cycle through hardware counters and accumulate totals */ for (cnt = 0; cnt < number_of_hardware_counters; cnt++) { const struct mali_counter *counter = &counters[cnt]; diff --git a/drivers/gator/gator_events_mali_midgard_hw_test.c b/drivers/gator/gator_events_mali_midgard_hw_test.c index 31a91e1c72b2..87c569cabf53 100644 --- a/drivers/gator/gator_events_mali_midgard_hw_test.c +++ b/drivers/gator/gator_events_mali_midgard_hw_test.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2012-2014. All rights reserved. + * Copyright (C) ARM Limited 2012-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/gator/gator_events_meminfo.c b/drivers/gator/gator_events_meminfo.c index c625ac5af9cd..985b312ab92b 100644 --- a/drivers/gator/gator_events_meminfo.c +++ b/drivers/gator/gator_events_meminfo.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -58,6 +58,8 @@ static ulong proc_enabled[PROC_COUNT]; static ulong proc_keys[PROC_COUNT]; static DEFINE_PER_CPU(long long, proc_buffer[2 * (PROC_COUNT + 3)]); +static void do_read(void); + #if USE_THREAD static int gator_meminfo_func(void *data); @@ -177,6 +179,7 @@ static int gator_events_meminfo_start(void) if (GATOR_REGISTER_TRACE(mm_page_alloc)) goto mm_page_alloc_exit; + do_read(); #if USE_THREAD /* Start worker thread */ gator_meminfo_run = true; diff --git a/drivers/gator/gator_events_mmapped.c b/drivers/gator/gator_events_mmapped.c index 6b2af995ed41..7b517611f8ec 100644 --- a/drivers/gator/gator_events_mmapped.c +++ b/drivers/gator/gator_events_mmapped.c @@ -1,7 +1,7 @@ /* * Example events provider * - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/gator/gator_events_net.c b/drivers/gator/gator_events_net.c index d21b4db7b77c..1e36731479d2 100644 --- a/drivers/gator/gator_events_net.c +++ b/drivers/gator/gator_events_net.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/gator/gator_events_perf_pmu.c b/drivers/gator/gator_events_perf_pmu.c index 47cf278e508b..f6b4f18ad11a 100644 --- a/drivers/gator/gator_events_perf_pmu.c +++ b/drivers/gator/gator_events_perf_pmu.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -23,11 +23,13 @@ extern bool event_based_sampling; /* Maximum number of per-core counters - currently reserves enough space for two full hardware PMUs for big.LITTLE */ #define CNTMAX 16 #define CCI_400 4 +#define CCI_500 8 #define CCN_5XX 8 /* Maximum number of uncore counters */ /* + 1 for the cci-400 cycles counter */ +/* cci-500 has no cycles counter */ /* + 1 for the CCN-5xx cycles counter */ -#define UCCNT (CCI_400 + 1 + CCN_5XX + 1) +#define UCCNT (CCI_400 + 1 + CCI_500 + CCN_5XX + 1) /* Default to 0 if unable to probe the revision which was the previous behavior */ #define DEFAULT_CCI_REVISION 0 @@ -58,9 +60,9 @@ static struct gator_attr uc_attrs[UCCNT]; static int uc_attr_count; struct gator_event { - int curr; - int prev; - int prev_delta; + uint32_t curr; + uint32_t prev; + uint32_t prev_delta; bool zero; struct perf_event *pevent; struct perf_event_attr *pevent_attr; @@ -315,7 +317,7 @@ static void gator_events_perf_pmu_stop(void) static void __read(int *const len, int cpu, struct gator_attr *const attr, struct gator_event *const event) { - int delta; + uint32_t delta; struct perf_event *const ev = event->pevent; if (ev != NULL && ev->state == PERF_EVENT_STATE_ACTIVE) { @@ -341,8 +343,6 @@ static void __read(int *const len, int cpu, struct gator_attr *const attr, struc event->prev_delta = delta; event->prev = event->curr; per_cpu(perf_cnt, cpu)[(*len)++] = attr->key; - if (delta < 0) - delta *= -1; per_cpu(perf_cnt, cpu)[(*len)++] = delta; } } @@ -436,13 +436,15 @@ static int probe_cci_revision(void) #endif -static void gator_events_perf_pmu_uncore_init(const char *const name, const int type, const int count) +static void gator_events_perf_pmu_uncore_init(const char *const name, const int type, const int count, const bool has_cycles_counter) { int cnt; - snprintf(uc_attrs[uc_attr_count].name, sizeof(uc_attrs[uc_attr_count].name), "%s_ccnt", name); - uc_attrs[uc_attr_count].type = type; - ++uc_attr_count; + if (has_cycles_counter) { + snprintf(uc_attrs[uc_attr_count].name, sizeof(uc_attrs[uc_attr_count].name), "%s_ccnt", name); + uc_attrs[uc_attr_count].type = type; + ++uc_attr_count; + } for (cnt = 0; cnt < count; ++cnt, ++uc_attr_count) { struct gator_attr *const attr = &uc_attrs[uc_attr_count]; @@ -452,7 +454,7 @@ static void gator_events_perf_pmu_uncore_init(const char *const name, const int } } -static void gator_events_perf_pmu_cci_init(const int type) +static void gator_events_perf_pmu_cci_400_init(const int type) { const char *cci_name; @@ -468,7 +470,7 @@ static void gator_events_perf_pmu_cci_init(const int type) return; } - gator_events_perf_pmu_uncore_init(cci_name, type, CCI_400); + gator_events_perf_pmu_uncore_init(cci_name, type, CCI_400, true); } static void gator_events_perf_pmu_cpu_init(const struct gator_cpu *const gator_cpu, const int type) @@ -535,9 +537,11 @@ int gator_events_perf_pmu_init(void) if (pe->pmu != NULL && type == pe->pmu->type) { if (strcmp("CCI", pe->pmu->name) == 0 || strcmp("CCI_400", pe->pmu->name) == 0 || strcmp("CCI_400-r1", pe->pmu->name) == 0) { - gator_events_perf_pmu_cci_init(type); + gator_events_perf_pmu_cci_400_init(type); + } else if (strcmp("CCI_500", pe->pmu->name) == 0) { + gator_events_perf_pmu_uncore_init("CCI_500", type, CCI_500, false); } else if (strcmp("ccn", pe->pmu->name) == 0) { - gator_events_perf_pmu_uncore_init("ARM_CCN_5XX", type, CCN_5XX); + gator_events_perf_pmu_uncore_init("ARM_CCN_5XX", type, CCN_5XX, true); } else if ((gator_cpu = gator_find_cpu_by_pmu_name(pe->pmu->name)) != NULL) { found_cpu = true; gator_events_perf_pmu_cpu_init(gator_cpu, type); @@ -549,10 +553,15 @@ int gator_events_perf_pmu_init(void) } if (!found_cpu) { - const struct gator_cpu *const gator_cpu = gator_find_cpu_by_cpuid(gator_cpuid()); + const struct gator_cpu *gator_cpu = gator_find_cpu_by_cpuid(gator_cpuid()); - if (gator_cpu == NULL) - return -1; + if (gator_cpu == NULL) { + gator_cpu = gator_find_cpu_by_cpuid(OTHER); + if (gator_cpu == NULL) { + pr_err("gator: Didn't find cpu\n"); + return -1; + } + } gator_events_perf_pmu_cpu_init(gator_cpu, PERF_TYPE_RAW); } diff --git a/drivers/gator/gator_events_sched.c b/drivers/gator/gator_events_sched.c index 637107d6af1d..463d83496073 100644 --- a/drivers/gator/gator_events_sched.c +++ b/drivers/gator/gator_events_sched.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/gator/gator_events_scorpion.c b/drivers/gator/gator_events_scorpion.c index 49219362db09..b51dcd39a8e1 100644 --- a/drivers/gator/gator_events_scorpion.c +++ b/drivers/gator/gator_events_scorpion.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2011-2014. All rights reserved. + * Copyright (C) ARM Limited 2011-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/gator/gator_hrtimer_gator.c b/drivers/gator/gator_hrtimer_gator.c index c1525e10a8da..36961f85b62a 100644 --- a/drivers/gator/gator_hrtimer_gator.c +++ b/drivers/gator/gator_hrtimer_gator.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2011-2014. All rights reserved. + * Copyright (C) ARM Limited 2011-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/gator/gator_iks.c b/drivers/gator/gator_iks.c index fb78c10fd987..80535c7b2b6e 100644 --- a/drivers/gator/gator_iks.c +++ b/drivers/gator/gator_iks.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/gator/gator_main.c b/drivers/gator/gator_main.c index 30bf60d95286..affa1dc312e4 100644 --- a/drivers/gator/gator_main.c +++ b/drivers/gator/gator_main.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -8,7 +8,7 @@ */ /* This version must match the gator daemon version */ -#define PROTOCOL_VERSION 20 +#define PROTOCOL_VERSION 21 static unsigned long gator_protocol_version = PROTOCOL_VERSION; #include @@ -28,6 +28,7 @@ static unsigned long gator_protocol_version = PROTOCOL_VERSION; #include #include "gator.h" +#include "gator_src_md5.h" #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32) #error kernels prior to 2.6.32 are not supported @@ -92,21 +93,17 @@ static unsigned long gator_protocol_version = PROTOCOL_VERSION; /* Name Frame Messages */ #define MESSAGE_COOKIE 1 #define MESSAGE_THREAD_NAME 2 -#define MESSAGE_LINK 4 /* Scheduler Trace Frame Messages */ #define MESSAGE_SCHED_SWITCH 1 #define MESSAGE_SCHED_EXIT 2 -/* Idle Frame Messages */ -#define MESSAGE_IDLE_ENTER 1 -#define MESSAGE_IDLE_EXIT 2 - /* Summary Frame Messages */ #define MESSAGE_SUMMARY 1 #define MESSAGE_CORE_NAME 3 /* Activity Frame Messages */ +#define MESSAGE_LINK 1 #define MESSAGE_SWITCH 2 #define MESSAGE_EXIT 3 @@ -267,6 +264,9 @@ GATOR_EVENTS_LIST * Misc ******************************************************************************/ +MODULE_PARM_DESC(gator_src_md5, "Gator driver source code md5sum"); +module_param_named(src_md5, gator_src_md5, charp, 0444); + static const struct gator_cpu gator_cpus[] = { { .cpuid = ARM1136, @@ -331,6 +331,13 @@ static const struct gator_cpu gator_cpus[] = { .dt_name = "arm,cortex-a15", .pmnc_counters = 6, }, + { + .cpuid = CORTEX_A12, + .core_name = "Cortex-A17", + .pmnc_name = "ARMv7_Cortex_A17", + .dt_name = "arm,cortex-a17", + .pmnc_counters = 6, + }, { .cpuid = CORTEX_A17, .core_name = "Cortex-A17", @@ -383,9 +390,10 @@ static const struct gator_cpu gator_cpus[] = { .pmnc_counters = 6, }, { - .cpuid = AARCH64, - .core_name = "AArch64", - .pmnc_name = "ARM_AArch64", + .cpuid = CORTEX_A72, + .core_name = "Cortex-A72", + .pmnc_name = "ARM_Cortex-A72", + .dt_name = "arm,cortex-a72", .pmnc_counters = 6, }, { @@ -443,7 +451,7 @@ u32 gator_cpuid(void) #else asm volatile("mrs %0, midr_el1" : "=r" (val)); #endif - return (val >> 4) & 0xfff; + return ((val & 0xff000000) >> 12) | ((val & 0xfff0) >> 4); #else return OTHER; #endif @@ -597,7 +605,7 @@ static void gator_send_core_name(const int cpu, const u32 cpuid) if (cpuid == -1) snprintf(core_name_buf, sizeof(core_name_buf), "Unknown"); else - snprintf(core_name_buf, sizeof(core_name_buf), "Unknown (0x%.3x)", cpuid); + snprintf(core_name_buf, sizeof(core_name_buf), "Unknown (0x%.5x)", cpuid); core_name = core_name_buf; } @@ -729,11 +737,11 @@ static void gator_emit_perf_time(u64 time) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) if (time >= gator_sync_time) { - int cpu = get_physical_cpu(); - marshal_event_single64(0, -1, local_clock()); gator_sync_time += NSEC_PER_SEC; - gator_commit_buffer(cpu, COUNTER_BUF, time); + if (gator_live_rate <= 0) { + gator_commit_buffer(get_physical_cpu(), COUNTER_BUF, time); + } } #endif } @@ -867,7 +875,9 @@ static void gator_summary(void) marshal_summary(timestamp, uptime, gator_monotonic_started, uname_buf); gator_sync_time = 0; - gator_emit_perf_time(gator_monotonic_started); + gator_emit_perf_time(gator_monotonic_started); + /* Always flush COUNTER_BUF so that the initial perf_time is received before it's used */ + gator_commit_buffer(get_physical_cpu(), COUNTER_BUF, 0); preempt_enable(); } diff --git a/drivers/gator/gator_marshaling.c b/drivers/gator/gator_marshaling.c index 0d1167643642..f5b81843d1c4 100644 --- a/drivers/gator/gator_marshaling.c +++ b/drivers/gator/gator_marshaling.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2012-2014. All rights reserved. + * Copyright (C) ARM Limited 2012-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -107,16 +107,16 @@ static void marshal_link(int cookie, int tgid, int pid) local_irq_save(flags); time = gator_get_time(); - if (buffer_check_space(cpu, NAME_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32)) { - gator_buffer_write_packed_int(cpu, NAME_BUF, MESSAGE_LINK); - gator_buffer_write_packed_int64(cpu, NAME_BUF, time); - gator_buffer_write_packed_int(cpu, NAME_BUF, cookie); - gator_buffer_write_packed_int(cpu, NAME_BUF, tgid); - gator_buffer_write_packed_int(cpu, NAME_BUF, pid); + if (buffer_check_space(cpu, ACTIVITY_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32)) { + gator_buffer_write_packed_int(cpu, ACTIVITY_BUF, MESSAGE_LINK); + gator_buffer_write_packed_int64(cpu, ACTIVITY_BUF, time); + gator_buffer_write_packed_int(cpu, ACTIVITY_BUF, cookie); + gator_buffer_write_packed_int(cpu, ACTIVITY_BUF, tgid); + gator_buffer_write_packed_int(cpu, ACTIVITY_BUF, pid); } local_irq_restore(flags); /* Check and commit; commit is set to occur once buffer is 3/4 full */ - buffer_check(cpu, NAME_BUF, time); + buffer_check(cpu, ACTIVITY_BUF, time); } static bool marshal_backtrace_header(int exec_cookie, int tgid, int pid, u64 time) diff --git a/drivers/gator/gator_trace_gpu.c b/drivers/gator/gator_trace_gpu.c index 5de9152e365a..d9b82ee1857f 100644 --- a/drivers/gator/gator_trace_gpu.c +++ b/drivers/gator/gator_trace_gpu.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/gator/gator_trace_power.c b/drivers/gator/gator_trace_power.c index 46e04b29a187..aaa8f8636c83 100644 --- a/drivers/gator/gator_trace_power.c +++ b/drivers/gator/gator_trace_power.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2011-2014. All rights reserved. + * Copyright (C) ARM Limited 2011-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -80,13 +80,7 @@ GATOR_DEFINE_PROBE(cpu_idle, TP_PROTO(unsigned int state, unsigned int cpu)) return; if (implements_wfi()) { - if (state == PWR_EVENT_EXIT) { - /* transition from wfi to non-wfi */ - marshal_idle(cpu, MESSAGE_IDLE_EXIT); - } else { - /* transition from non-wfi to wfi */ - marshal_idle(cpu, MESSAGE_IDLE_ENTER); - } + marshal_idle(cpu, state); } per_cpu(idle_prev_state, cpu) = state; diff --git a/drivers/gator/gator_trace_sched.c b/drivers/gator/gator_trace_sched.c index 6d7cbd7348e1..ad7c39e14a17 100644 --- a/drivers/gator/gator_trace_sched.c +++ b/drivers/gator/gator_trace_sched.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/gator/mali/mali_kbase_gator_api.h b/drivers/gator/mali/mali_kbase_gator_api.h deleted file mode 100644 index 5ed069797e36..000000000000 --- a/drivers/gator/mali/mali_kbase_gator_api.h +++ /dev/null @@ -1,219 +0,0 @@ -/** - * Copyright (C) ARM Limited 2014. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#ifndef _KBASE_GATOR_API_H_ -#define _KBASE_GATOR_API_H_ - -/** - * @brief This file describes the API used by Gator to collect hardware counters data from a Mali device. - */ - -/* This define is used by the gator kernel module compile to select which DDK - * API calling convention to use. If not defined (legacy DDK) gator assumes - * version 1. The version to DDK release mapping is: - * Version 1 API: DDK versions r1px, r2px - * Version 2 API: DDK versions r3px, r4px - * Version 3 API: DDK version r5p0 and newer - * - * API Usage - * ========= - * - * 1] Call kbase_gator_hwcnt_init_names() to return the list of short counter - * names for the GPU present in this device. - * - * 2] Create a kbase_gator_hwcnt_info structure and set the counter enables for - * the counters you want enabled. The enables can all be set for simplicity in - * most use cases, but disabling some will let you minimize bandwidth impact. - * - * 3] Call kbase_gator_hwcnt_init() using the above structure, to create a - * counter context. On successful return the DDK will have populated the - * structure with a variety of useful information. - * - * 4] Call kbase_gator_hwcnt_dump_irq() to queue a non-blocking request for a - * counter dump. If this returns a non-zero value the request has been queued, - * otherwise the driver has been unable to do so (typically because of another - * user of the instrumentation exists concurrently). - * - * 5] Call kbase_gator_hwcnt_dump_complete() to test whether the previously - * requested dump has been succesful. If this returns non-zero the counter dump - * has resolved, but the value of *success must also be tested as the dump - * may have not been successful. If it returns zero the counter dump was - * abandoned due to the device being busy (typically because of another - * user of the instrumentation exists concurrently). - * - * 6] Process the counters stored in the buffer pointed to by ... - * - * kbase_gator_hwcnt_info->kernel_dump_buffer - * - * In pseudo code you can find all of the counters via this approach: - * - * - * hwcnt_info # pointer to kbase_gator_hwcnt_info structure - * hwcnt_name # pointer to name list - * - * u32 * hwcnt_data = (u32*)hwcnt_info->kernel_dump_buffer - * - * # Iterate over each 64-counter block in this GPU configuration - * for( i = 0; i < hwcnt_info->nr_hwc_blocks; i++) { - * hwc_type type = hwcnt_info->hwc_layout[i]; - * - * # Skip reserved type blocks - they contain no counters at all - * if( type == RESERVED_BLOCK ) { - * continue; - * } - * - * size_t name_offset = type * 64; - * size_t data_offset = i * 64; - * - * # Iterate over the names of the counters in this block type - * for( j = 0; j < 64; j++) { - * const char * name = hwcnt_name[name_offset+j]; - * - * # Skip empty name strings - there is no counter here - * if( name[0] == '\0' ) { - * continue; - * } - * - * u32 data = hwcnt_data[data_offset+j]; - * - * printk( "COUNTER: %s DATA: %u\n", name, data ); - * } - * } - * - * - * Note that in most implementations you typically want to either SUM or - * AVERAGE multiple instances of the same counter if, for example, you have - * multiple shader cores or multiple L2 caches. The most sensible view for - * analysis is to AVERAGE shader core counters, but SUM L2 cache and MMU - * counters. - * - * 7] Goto 4, repeating until you want to stop collecting counters. - * - * 8] Release the dump resources by calling kbase_gator_hwcnt_term(). - * - * 9] Release the name table resources by calling kbase_gator_hwcnt_term_names(). - * This function must only be called if init_names() returned a non-NULL value. - **/ - -#define MALI_DDK_GATOR_API_VERSION 3 - -#if !defined(MALI_TRUE) - #define MALI_TRUE ((uint32_t)1) -#endif - -#if !defined(MALI_FALSE) - #define MALI_FALSE ((uint32_t)0) -#endif - -enum hwc_type { - JM_BLOCK = 0, - TILER_BLOCK, - SHADER_BLOCK, - MMU_L2_BLOCK, - RESERVED_BLOCK -}; - -struct kbase_gator_hwcnt_info { - - /* Passed from Gator to kbase */ - - /* the bitmask of enabled hardware counters for each counter block */ - uint16_t bitmask[4]; - - /* Passed from kbase to Gator */ - - /* ptr to counter dump memory */ - void *kernel_dump_buffer; - - /* size of counter dump memory */ - uint32_t size; - - /* the ID of the Mali device */ - uint32_t gpu_id; - - /* the number of shader cores in the GPU */ - uint32_t nr_cores; - - /* the number of core groups */ - uint32_t nr_core_groups; - - /* the memory layout of the performance counters */ - enum hwc_type *hwc_layout; - - /* the total number of hardware couter blocks */ - uint32_t nr_hwc_blocks; -}; - -/** - * @brief Opaque block of Mali data which Gator needs to return to the API later. - */ -struct kbase_gator_hwcnt_handles; - -/** - * @brief Initialize the resources Gator needs for performance profiling. - * - * @param in_out_info A pointer to a structure containing the enabled counters passed from Gator and all the Mali - * specific information that will be returned to Gator. On entry Gator must have populated the - * 'bitmask' field with the counters it wishes to enable for each class of counter block. - * Each entry in the array corresponds to a single counter class based on the "hwc_type" - * enumeration, and each bit corresponds to an enable for 4 sequential counters (LSB enables - * the first 4 counters in the block, and so on). See the GPU counter array as returned by - * kbase_gator_hwcnt_get_names() for the index values of each counter for the curernt GPU. - * - * @return Pointer to an opaque handle block on success, NULL on error. - */ -extern struct kbase_gator_hwcnt_handles *kbase_gator_hwcnt_init(struct kbase_gator_hwcnt_info *in_out_info); - -/** - * @brief Free all resources once Gator has finished using performance counters. - * - * @param in_out_info A pointer to a structure containing the enabled counters passed from Gator and all the - * Mali specific information that will be returned to Gator. - * @param opaque_handles A wrapper structure for kbase structures. - */ -extern void kbase_gator_hwcnt_term(struct kbase_gator_hwcnt_info *in_out_info, struct kbase_gator_hwcnt_handles *opaque_handles); - -/** - * @brief Poll whether a counter dump is successful. - * - * @param opaque_handles A wrapper structure for kbase structures. - * @param[out] success Non-zero on success, zero on failure. - * - * @return Zero if the dump is still pending, non-zero if the dump has completed. Note that a - * completed dump may not have dumped succesfully, so the caller must test for both - * a completed and successful dump before processing counters. - */ -extern uint32_t kbase_gator_instr_hwcnt_dump_complete(struct kbase_gator_hwcnt_handles *opaque_handles, uint32_t * const success); - -/** - * @brief Request the generation of a new counter dump. - * - * @param opaque_handles A wrapper structure for kbase structures. - * - * @return Zero if the hardware device is busy and cannot handle the request, non-zero otherwise. - */ -extern uint32_t kbase_gator_instr_hwcnt_dump_irq(struct kbase_gator_hwcnt_handles *opaque_handles); - -/** - * @brief This function is used to fetch the names table based on the Mali device in use. - * - * @param[out] total_number_of_counters The total number of counters short names in the Mali devices' list. - * - * @return Pointer to an array of strings of length *total_number_of_counters. - */ -extern const char * const *kbase_gator_hwcnt_init_names(uint32_t *total_number_of_counters); - -/** - * @brief This function is used to terminate the use of the names table. - * - * This function must only be called if the initial call to kbase_gator_hwcnt_init_names returned a non-NULL value. - */ -extern void kbase_gator_hwcnt_term_names(void); - -#endif diff --git a/drivers/gator/mali/mali_mjollnir_profiling_gator_api.h b/drivers/gator/mali/mali_mjollnir_profiling_gator_api.h index 2bc0b037eee6..a5d165157396 100644 --- a/drivers/gator/mali/mali_mjollnir_profiling_gator_api.h +++ b/drivers/gator/mali/mali_mjollnir_profiling_gator_api.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/gator/mali/mali_utgard_profiling_gator_api.h b/drivers/gator/mali/mali_utgard_profiling_gator_api.h index d6465312628e..f550490c2c39 100644 --- a/drivers/gator/mali/mali_utgard_profiling_gator_api.h +++ b/drivers/gator/mali/mali_utgard_profiling_gator_api.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/gator/mali_midgard.mk b/drivers/gator/mali_midgard.mk index 1b784d5c3d58..b0076c22da6b 100644 --- a/drivers/gator/mali_midgard.mk +++ b/drivers/gator/mali_midgard.mk @@ -23,6 +23,7 @@ endif ifneq ($(wildcard $(DDK_DIR)/drivers/gpu/arm/midgard/mali_kbase_gator_api.h),) EXTRA_CFLAGS += -DMALI_SIMPLE_API=1 +EXTRA_CFLAGS += -I$(DDK_DIR)/drivers/gpu/arm/midgard endif UMP_DIR = $(DDK_DIR)/include/linux diff --git a/tools/gator/daemon/Android.mk b/tools/gator/daemon/Android.mk index 970ac6946150..68f4a8397379 100644 --- a/tools/gator/daemon/Android.mk +++ b/tools/gator/daemon/Android.mk @@ -1,13 +1,12 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -XML_H := $(shell cd $(LOCAL_PATH) && make events_xml.h defaults_xml.h) +XML_H := $(shell cd $(LOCAL_PATH) && make events_xml.h defaults_xml.h SrcMd5.cpp) LOCAL_SRC_FILES := \ AnnotateListener.cpp \ Buffer.cpp \ CCNDriver.cpp \ - CPUFreqDriver.cpp \ CapturedXML.cpp \ Child.cpp \ Command.cpp \ @@ -43,6 +42,7 @@ LOCAL_SRC_FILES := \ SessionXML.cpp \ Setup.cpp \ Source.cpp \ + SrcMd5.cpp \ StreamlineSetup.cpp \ UEvent.cpp \ UserSpaceSource.cpp \ diff --git a/tools/gator/daemon/AnnotateListener.cpp b/tools/gator/daemon/AnnotateListener.cpp index 50110b4dc84c..5966cbea8d13 100644 --- a/tools/gator/daemon/AnnotateListener.cpp +++ b/tools/gator/daemon/AnnotateListener.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2014. All rights reserved. + * Copyright (C) ARM Limited 2014-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -12,36 +12,56 @@ #include "OlySocket.h" +static const char STREAMLINE_ANNOTATE_PARENT[] = "\0streamline-annotate-parent"; + struct AnnotateClient { AnnotateClient *next; int fd; }; -AnnotateListener::AnnotateListener() : mClients(NULL), mSock(NULL) { +AnnotateListener::AnnotateListener() : mClients(NULL), mSock(NULL), mUds(NULL) { } AnnotateListener::~AnnotateListener() { close(); + delete mUds; delete mSock; } void AnnotateListener::setup() { mSock = new OlyServerSocket(8082); + mUds = new OlyServerSocket(STREAMLINE_ANNOTATE_PARENT, sizeof(STREAMLINE_ANNOTATE_PARENT), true); } -int AnnotateListener::getFd() { +int AnnotateListener::getSockFd() { return mSock->getFd(); } -void AnnotateListener::handle() { +void AnnotateListener::handleSock() { AnnotateClient *const client = new AnnotateClient(); client->fd = mSock->acceptConnection(); client->next = mClients; mClients = client; } +int AnnotateListener::getUdsFd() { + return mUds->getFd(); +} + +void AnnotateListener::handleUds() { + AnnotateClient *const client = new AnnotateClient(); + client->fd = mUds->acceptConnection(); + client->next = mClients; + mClients = client; +} + void AnnotateListener::close() { - mSock->closeServerSocket(); + if (mUds != NULL) { + mUds->closeServerSocket(); + } + if (mSock != NULL) { + mSock->closeServerSocket(); + } while (mClients != NULL) { ::close(mClients->fd); AnnotateClient *next = mClients->next; diff --git a/tools/gator/daemon/AnnotateListener.h b/tools/gator/daemon/AnnotateListener.h index cdefef12db22..6bc747d42d18 100644 --- a/tools/gator/daemon/AnnotateListener.h +++ b/tools/gator/daemon/AnnotateListener.h @@ -1,12 +1,15 @@ /** - * Copyright (C) ARM Limited 2014. All rights reserved. + * Copyright (C) ARM Limited 2014-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -class AnnotateClient; +#ifndef ANNOTATELISTENER_H +#define ANNOTATELISTENER_H + +struct AnnotateClient; class OlyServerSocket; class AnnotateListener { @@ -15,17 +18,22 @@ public: ~AnnotateListener(); void setup(); - int getFd(); + int getSockFd(); + int getUdsFd(); - void handle(); + void handleSock(); + void handleUds(); void close(); void signal(); private: AnnotateClient *mClients; OlyServerSocket *mSock; + OlyServerSocket *mUds; // Intentionally unimplemented AnnotateListener(const AnnotateListener &); AnnotateListener &operator=(const AnnotateListener &); }; + +#endif // ANNOTATELISTENER_H diff --git a/tools/gator/daemon/Application.mk b/tools/gator/daemon/Application.mk index 3ada471cac19..8b0a7882e938 100644 --- a/tools/gator/daemon/Application.mk +++ b/tools/gator/daemon/Application.mk @@ -1,3 +1,3 @@ -APP_PLATFORM := android-8 +APP_PLATFORM := android-9 # Replace armeabi-v7a with arm64-v8a to build an arm64 gatord or with armeabi to build an ARM11 gatord APP_ABI := armeabi-v7a diff --git a/tools/gator/daemon/Buffer.cpp b/tools/gator/daemon/Buffer.cpp index 8fa628015069..c4ced9f607f9 100644 --- a/tools/gator/daemon/Buffer.cpp +++ b/tools/gator/daemon/Buffer.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -13,17 +13,19 @@ #include "SessionData.h" #define mask (mSize - 1) +#define FRAME_HEADER_SIZE 3 enum { - CODE_PEA = 1, - CODE_KEYS = 2, - CODE_FORMAT = 3, - CODE_MAPS = 4, - CODE_COMM = 5, - CODE_KEYS_OLD = 6, - CODE_ONLINE_CPU = 7, - CODE_OFFLINE_CPU = 8, - CODE_KALLSYMS = 9, + CODE_PEA = 1, + CODE_KEYS = 2, + CODE_FORMAT = 3, + CODE_MAPS = 4, + CODE_COMM = 5, + CODE_KEYS_OLD = 6, + CODE_ONLINE_CPU = 7, + CODE_OFFLINE_CPU = 8, + CODE_KALLSYMS = 9, + CODE_COUNTERS = 10, }; // Summary Frame Messages @@ -47,7 +49,7 @@ enum { Buffer::Buffer(const int32_t core, const int32_t buftype, const int size, sem_t *const readerSem) : mBuf(new char[size]), mReaderSem(readerSem), mCommitTime(gSessionData->mLiveRate), mSize(size), mReadPos(0), mWritePos(0), mCommitPos(0), mAvailable(true), mIsDone(false), mCore(core), mBufType(buftype) { if ((mSize & mask) != 0) { - logg->logError(__FILE__, __LINE__, "Buffer size is not a power of 2"); + logg->logError("Buffer size is not a power of 2"); handleException(); } sem_init(&mWriterSem, 0, 0); @@ -141,7 +143,7 @@ int Buffer::contiguousSpaceAvailable() const { } } -void Buffer::commit(const uint64_t time) { +void Buffer::commit(const uint64_t time, const bool force) { // post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload const int typeLength = gSessionData->mLocalCapture ? 0 : 1; int length = mWritePos - mCommitPos; @@ -149,6 +151,10 @@ void Buffer::commit(const uint64_t time) { length += mSize; } length = length - typeLength - sizeof(int32_t); + if (!force && !mIsDone && length <= FRAME_HEADER_SIZE) { + // Nothing to write, only the frame header is present + return; + } for (size_t byte = 0; byte < sizeof(int32_t); byte++) { mBuf[(mCommitPos + typeLength + byte) & mask] = (length >> byte * 8) & 0xFF; } @@ -317,7 +323,7 @@ void Buffer::event64(const int key, const int64_t value) { } } -void Buffer::pea(const uint64_t currTime, const struct perf_event_attr *const pea, int key) { +void Buffer::marshalPea(const uint64_t currTime, const struct perf_event_attr *const pea, int key) { while (!checkSpace(2 * MAXSIZE_PACK32 + pea->size)) { sem_wait(&mWriterSem); } @@ -327,7 +333,7 @@ void Buffer::pea(const uint64_t currTime, const struct perf_event_attr *const pe check(currTime); } -void Buffer::keys(const uint64_t currTime, const int count, const __u64 *const ids, const int *const keys) { +void Buffer::marshalKeys(const uint64_t currTime, const int count, const __u64 *const ids, const int *const keys) { while (!checkSpace(2 * MAXSIZE_PACK32 + count * (MAXSIZE_PACK32 + MAXSIZE_PACK64))) { sem_wait(&mWriterSem); } @@ -340,7 +346,7 @@ void Buffer::keys(const uint64_t currTime, const int count, const __u64 *const i check(currTime); } -void Buffer::keysOld(const uint64_t currTime, const int keyCount, const int *const keys, const int bytes, const char *const buf) { +void Buffer::marshalKeysOld(const uint64_t currTime, const int keyCount, const int *const keys, const int bytes, const char *const buf) { while (!checkSpace((2 + keyCount) * MAXSIZE_PACK32 + bytes)) { sem_wait(&mWriterSem); } @@ -353,7 +359,7 @@ void Buffer::keysOld(const uint64_t currTime, const int keyCount, const int *con check(currTime); } -void Buffer::format(const uint64_t currTime, const int length, const char *const format) { +void Buffer::marshalFormat(const uint64_t currTime, const int length, const char *const format) { while (!checkSpace(MAXSIZE_PACK32 + length + 1)) { sem_wait(&mWriterSem); } @@ -362,7 +368,7 @@ void Buffer::format(const uint64_t currTime, const int length, const char *const check(currTime); } -void Buffer::maps(const uint64_t currTime, const int pid, const int tid, const char *const maps) { +void Buffer::marshalMaps(const uint64_t currTime, const int pid, const int tid, const char *const maps) { const int mapsLen = strlen(maps) + 1; while (!checkSpace(3 * MAXSIZE_PACK32 + mapsLen)) { sem_wait(&mWriterSem); @@ -374,7 +380,7 @@ void Buffer::maps(const uint64_t currTime, const int pid, const int tid, const c check(currTime); } -void Buffer::comm(const uint64_t currTime, const int pid, const int tid, const char *const image, const char *const comm) { +void Buffer::marshalComm(const uint64_t currTime, const int pid, const int tid, const char *const image, const char *const comm) { const int imageLen = strlen(image) + 1; const int commLen = strlen(comm) + 1; while (!checkSpace(3 * MAXSIZE_PACK32 + imageLen + commLen)) { @@ -388,27 +394,27 @@ void Buffer::comm(const uint64_t currTime, const int pid, const int tid, const c check(currTime); } -void Buffer::onlineCPU(const uint64_t currTime, const uint64_t time, const int cpu) { +void Buffer::onlineCPU(const uint64_t currTime, const int cpu) { while (!checkSpace(MAXSIZE_PACK32 + MAXSIZE_PACK64)) { sem_wait(&mWriterSem); } packInt(CODE_ONLINE_CPU); - packInt64(time); + packInt64(currTime); packInt(cpu); check(currTime); } -void Buffer::offlineCPU(const uint64_t currTime, const uint64_t time, const int cpu) { +void Buffer::offlineCPU(const uint64_t currTime, const int cpu) { while (!checkSpace(MAXSIZE_PACK32 + MAXSIZE_PACK64)) { sem_wait(&mWriterSem); } packInt(CODE_OFFLINE_CPU); - packInt64(time); + packInt64(currTime); packInt(cpu); check(currTime); } -void Buffer::kallsyms(const uint64_t currTime, const char *const kallsyms) { +void Buffer::marshalKallsyms(const uint64_t currTime, const char *const kallsyms) { const int kallsymsLen = strlen(kallsyms) + 1; while (!checkSpace(3 * MAXSIZE_PACK32 + kallsymsLen)) { sem_wait(&mWriterSem); @@ -418,6 +424,31 @@ void Buffer::kallsyms(const uint64_t currTime, const char *const kallsyms) { check(currTime); } +void Buffer::perfCounterHeader(const uint64_t time) { + while (!checkSpace(MAXSIZE_PACK32 + MAXSIZE_PACK64)) { + sem_wait(&mWriterSem); + } + packInt(CODE_COUNTERS); + packInt64(time); +} + +void Buffer::perfCounter(const int core, const int key, const int64_t value) { + while (!checkSpace(2*MAXSIZE_PACK32 + MAXSIZE_PACK64)) { + sem_wait(&mWriterSem); + } + packInt(core); + packInt(key); + packInt64(value); +} + +void Buffer::perfCounterFooter(const uint64_t currTime) { + while (!checkSpace(MAXSIZE_PACK32)) { + sem_wait(&mWriterSem); + } + packInt(-1); + check(currTime); +} + void Buffer::setDone() { mIsDone = true; commit(0); diff --git a/tools/gator/daemon/Buffer.h b/tools/gator/daemon/Buffer.h index 6cffd8e39a36..13c44e1fd359 100644 --- a/tools/gator/daemon/Buffer.h +++ b/tools/gator/daemon/Buffer.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -36,7 +36,7 @@ public: int bytesAvailable() const; int contiguousSpaceAvailable() const; - void commit(const uint64_t time); + void commit(const uint64_t time, const bool force = false); void check(const uint64_t time); // Summary messages @@ -50,15 +50,18 @@ public: void event64(int key, int64_t value); // Perf Attrs messages - void pea(const uint64_t currTime, const struct perf_event_attr *const pea, int key); - void keys(const uint64_t currTime, const int count, const __u64 *const ids, const int *const keys); - void keysOld(const uint64_t currTime, const int keyCount, const int *const keys, const int bytes, const char *const buf); - void format(const uint64_t currTime, const int length, const char *const format); - void maps(const uint64_t currTime, const int pid, const int tid, const char *const maps); - void comm(const uint64_t currTime, const int pid, const int tid, const char *const image, const char *const comm); - void onlineCPU(const uint64_t currTime, const uint64_t time, const int cpu); - void offlineCPU(const uint64_t currTime, const uint64_t time, const int cpu); - void kallsyms(const uint64_t currTime, const char *const kallsyms); + void marshalPea(const uint64_t currTime, const struct perf_event_attr *const pea, int key); + void marshalKeys(const uint64_t currTime, const int count, const __u64 *const ids, const int *const keys); + void marshalKeysOld(const uint64_t currTime, const int keyCount, const int *const keys, const int bytes, const char *const buf); + void marshalFormat(const uint64_t currTime, const int length, const char *const format); + void marshalMaps(const uint64_t currTime, const int pid, const int tid, const char *const maps); + void marshalComm(const uint64_t currTime, const int pid, const int tid, const char *const image, const char *const comm); + void onlineCPU(const uint64_t currTime, const int cpu); + void offlineCPU(const uint64_t currTime, const int cpu); + void marshalKallsyms(const uint64_t currTime, const char *const kallsyms); + void perfCounterHeader(const uint64_t time); + void perfCounter(const int core, const int key, const int64_t value); + void perfCounterFooter(const uint64_t currTime); void setDone(); bool isDone() const; diff --git a/tools/gator/daemon/CCNDriver.cpp b/tools/gator/daemon/CCNDriver.cpp index dd1a2b133842..d77513acc4e4 100644 --- a/tools/gator/daemon/CCNDriver.cpp +++ b/tools/gator/daemon/CCNDriver.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2014. All rights reserved. + * Copyright (C) ARM Limited 2014-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -28,7 +28,6 @@ static const char TAG_OPTION_SET[] = "option_set"; static const char ATTR_AVERAGE_SELECTION[] = "average_selection"; static const char ATTR_COUNTER[] = "counter"; -static const char ATTR_COUNTER_SET[] = "counter_set"; static const char ATTR_COUNT[] = "count"; static const char ATTR_DESCRIPTION[] = "description"; static const char ATTR_DISPLAY[] = "display"; @@ -110,7 +109,7 @@ void CCNDriver::readEvents(mxml_node_t *const) { int type; if (DriverSource::readIntDriver("/sys/bus/event_source/devices/ccn/type", &type) != 0) { - logg->logError(__FILE__, __LINE__, "Unable to read CCN-5xx type"); + logg->logError("Unable to read CCN-5xx type"); handleException(); } diff --git a/tools/gator/daemon/CCNDriver.h b/tools/gator/daemon/CCNDriver.h index fb4c717e969a..06ac33f07a36 100644 --- a/tools/gator/daemon/CCNDriver.h +++ b/tools/gator/daemon/CCNDriver.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2014. All rights reserved. + * Copyright (C) ARM Limited 2014-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/COPYING b/tools/gator/daemon/COPYING new file mode 100644 index 000000000000..d159169d1050 --- /dev/null +++ b/tools/gator/daemon/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/tools/gator/daemon/CPUFreqDriver.cpp b/tools/gator/daemon/CPUFreqDriver.cpp deleted file mode 100644 index 41f9d6f2b3f4..000000000000 --- a/tools/gator/daemon/CPUFreqDriver.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include "CPUFreqDriver.h" - -#include "Buffer.h" -#include "DriverSource.h" -#include "Logging.h" -#include "SessionData.h" - -CPUFreqDriver::CPUFreqDriver() : mPrev() { -} - -CPUFreqDriver::~CPUFreqDriver() { -} - -void CPUFreqDriver::readEvents(mxml_node_t *const) { - // Only for use with perf - if (!gSessionData->perf.isSetup()) { - return; - } - - setCounters(new DriverCounter(getCounters(), strdup("Linux_power_cpu_freq"))); -} - -void CPUFreqDriver::read(Buffer *const buffer) { - char buf[64]; - const DriverCounter *const counter = getCounters(); - if ((counter == NULL) || !counter->isEnabled()) { - return; - } - - const int key = getCounters()->getKey(); - bool resetCores = false; - for (int i = 0; i < gSessionData->mCores; ++i) { - snprintf(buf, sizeof(buf), "/sys/devices/system/cpu/cpu%i/cpufreq/cpuinfo_cur_freq", i); - int64_t freq; - if (DriverSource::readInt64Driver(buf, &freq) != 0) { - freq = 0; - } - if (mPrev[i] != freq) { - mPrev[i] = freq; - // Change cores - buffer->event64(2, i); - resetCores = true; - buffer->event64(key, 1000*freq); - } - } - if (resetCores) { - // Revert cores, UserSpaceSource is all on core 0 - buffer->event64(2, 0); - } -} diff --git a/tools/gator/daemon/CPUFreqDriver.h b/tools/gator/daemon/CPUFreqDriver.h deleted file mode 100644 index ad8c9aaa9e7d..000000000000 --- a/tools/gator/daemon/CPUFreqDriver.h +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef CPUFREQDRIVER_H -#define CPUFREQDRIVER_H - -#include "Config.h" -#include "Driver.h" - -class CPUFreqDriver : public PolledDriver { -private: - typedef PolledDriver super; - -public: - CPUFreqDriver(); - ~CPUFreqDriver(); - - void readEvents(mxml_node_t *const root); - void read(Buffer *const buffer); - -private: - int64_t mPrev[NR_CPUS]; - - // Intentionally unimplemented - CPUFreqDriver(const CPUFreqDriver &); - CPUFreqDriver &operator=(const CPUFreqDriver &); -}; - -#endif // CPUFREQDRIVER_H diff --git a/tools/gator/daemon/CapturedXML.cpp b/tools/gator/daemon/CapturedXML.cpp index 0b5802c893bb..1854c77dcb0e 100644 --- a/tools/gator/daemon/CapturedXML.cpp +++ b/tools/gator/daemon/CapturedXML.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -34,7 +34,6 @@ mxml_node_t* CapturedXML::getTree(bool includeTime) { mxmlElementSetAttr(captured, "version", "1"); if (gSessionData->perf.isSetup()) { mxmlElementSetAttr(captured, "type", "Perf"); - mxmlElementSetAttr(captured, "perf_beta", "yes"); } mxmlElementSetAttrf(captured, "protocol", "%d", PROTOCOL_VERSION); if (includeTime) { // Send the following only after the capture is complete @@ -98,7 +97,7 @@ void CapturedXML::write(char* path) { char* xml = getXML(true); if (util->writeToDisk(file, xml) < 0) { - logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify the path.", file); + logg->logError("Error writing %s\nPlease verify the path.", file); handleException(); } diff --git a/tools/gator/daemon/CapturedXML.h b/tools/gator/daemon/CapturedXML.h index b704f6e53bb5..69d80c09b514 100644 --- a/tools/gator/daemon/CapturedXML.h +++ b/tools/gator/daemon/CapturedXML.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/Child.cpp b/tools/gator/daemon/Child.cpp index 6b5bbb3bf6af..a19e9cf86805 100644 --- a/tools/gator/daemon/Child.cpp +++ b/tools/gator/daemon/Child.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -150,13 +150,12 @@ static void *senderThread(void *) { prctl(PR_SET_NAME, (unsigned long)&"gatord-sender", 0, 0, 0); sem_wait(&haltPipeline); - while (!primarySource->isDone() || - !externalSource->isDone() || + while (!externalSource->isDone() || (userSpaceSource != NULL && !userSpaceSource->isDone()) || - (ftraceSource != NULL && !ftraceSource->isDone())) { + (ftraceSource != NULL && !ftraceSource->isDone()) || + !primarySource->isDone()) { sem_wait(&senderSem); - primarySource->write(sender); externalSource->write(sender); if (userSpaceSource != NULL) { userSpaceSource->write(sender); @@ -164,6 +163,7 @@ static void *senderThread(void *) { if (ftraceSource != NULL) { ftraceSource->write(sender); } + primarySource->write(sender); } // write end-of-capture sequence @@ -232,7 +232,7 @@ void Child::run() { sender = new Sender(socket); if (mNumConnections > 1) { - logg->logError(__FILE__, __LINE__, "Session already in progress"); + logg->logError("Session already in progress"); handleException(); } @@ -267,7 +267,7 @@ void Child::run() { char* xmlString; xmlString = util->readFromDisk(gSessionData->mSessionXMLPath); if (xmlString == 0) { - logg->logError(__FILE__, __LINE__, "Unable to read session xml file: %s", gSessionData->mSessionXMLPath); + logg->logError("Unable to read session xml file: %s", gSessionData->mSessionXMLPath); handleException(); } gSessionData->parseSessionXML(xmlString); @@ -280,16 +280,27 @@ void Child::run() { } if (gSessionData->kmod.isMaliCapture() && (gSessionData->mSampleRate == 0)) { - logg->logError(__FILE__, __LINE__, "Mali counters are not supported with Sample Rate: None."); + logg->logError("Mali counters are not supported with Sample Rate: None."); handleException(); } + // Initialize ftrace source before child as it's slow and dependens on nothing else + // If initialized later, us gator with ftrace has time sync issues + if (gSessionData->ftraceDriver.countersEnabled()) { + ftraceSource = new FtraceSource(&senderSem); + if (!ftraceSource->prepare()) { + logg->logError("Unable to prepare userspace source for capture"); + handleException(); + } + ftraceSource->start(); + } + // Must be after session XML is parsed if (!primarySource->prepare()) { if (gSessionData->perf.isSetup()) { - logg->logError(__FILE__, __LINE__, "Unable to prepare gator driver for capture"); + logg->logError("Unable to communicate with the perf API, please ensure that CONFIG_TRACING and CONFIG_CONTEXT_SWITCH_TRACER are enabled. Please refer to README_Streamline.txt for more information."); } else { - logg->logError(__FILE__, __LINE__, "Unable to communicate with the perf API, please ensure that CONFIG_TRACING and CONFIG_CONTEXT_SWITCH_TRACER are enabled. Please refer to README_Streamline.txt for more information."); + logg->logError("Unable to prepare gator driver for capture"); } handleException(); } @@ -300,7 +311,7 @@ void Child::run() { // Must be initialized before senderThread is started as senderThread checks externalSource externalSource = new ExternalSource(&senderSem); if (!externalSource->prepare()) { - logg->logError(__FILE__, __LINE__, "Unable to prepare external source for capture"); + logg->logError("Unable to prepare external source for capture"); handleException(); } externalSource->start(); @@ -324,21 +335,12 @@ void Child::run() { if (startUSSource) { userSpaceSource = new UserSpaceSource(&senderSem); if (!userSpaceSource->prepare()) { - logg->logError(__FILE__, __LINE__, "Unable to prepare userspace source for capture"); + logg->logError("Unable to prepare userspace source for capture"); handleException(); } userSpaceSource->start(); } - if (gSessionData->ftraceDriver.countersEnabled()) { - ftraceSource = new FtraceSource(&senderSem); - if (!ftraceSource->prepare()) { - logg->logError(__FILE__, __LINE__, "Unable to prepare userspace source for capture"); - handleException(); - } - ftraceSource->start(); - } - if (gSessionData->mAllowCommands && (gSessionData->mCaptureCommand != NULL)) { pthread_t thread; if (pthread_create(&thread, NULL, commandThread, NULL)) { @@ -347,7 +349,7 @@ void Child::run() { } if (!thread_creation_success) { - logg->logError(__FILE__, __LINE__, "Failed to create gator threads"); + logg->logError("Failed to create gator threads"); handleException(); } @@ -357,6 +359,7 @@ void Child::run() { // Start profiling primarySource->run(); + // Wait for the other threads to exit if (ftraceSource != NULL) { ftraceSource->join(); } @@ -364,8 +367,6 @@ void Child::run() { userSpaceSource->join(); } externalSource->join(); - - // Wait for the other threads to exit pthread_join(senderThreadID, NULL); // Shutting down the connection should break the stop thread which is stalling on the socket recv() function diff --git a/tools/gator/daemon/Child.h b/tools/gator/daemon/Child.h index cc78202ceb5c..a6c54db70a70 100644 --- a/tools/gator/daemon/Child.h +++ b/tools/gator/daemon/Child.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/Command.cpp b/tools/gator/daemon/Command.cpp index 28d73cf5a905..0a6e3b9901ee 100644 --- a/tools/gator/daemon/Command.cpp +++ b/tools/gator/daemon/Command.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2014. All rights reserved. + * Copyright (C) ARM Limited 2014-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -39,7 +39,7 @@ static int getUid(const char *const name, char *const shPath, const char *const const int pid = fork(); if (pid < 0) { - logg->logError(__FILE__, __LINE__, "fork failed"); + logg->logError("fork failed"); handleException(); } if (pid == 0) { @@ -94,7 +94,7 @@ void *commandThread(void *) { const char *const name = gSessionData->mCaptureUser == NULL ? "nobody" : gSessionData->mCaptureUser; const int uid = getUid(name); if (uid < 0) { - logg->logError(__FILE__, __LINE__, "Unable to lookup the user %s, please double check that the user exists", name); + logg->logError("Unable to look up the user %s, please double check that the user exists", name); handleException(); } @@ -103,13 +103,13 @@ void *commandThread(void *) { char buf[128]; int pipefd[2]; if (pipe_cloexec(pipefd) != 0) { - logg->logError(__FILE__, __LINE__, "pipe failed"); + logg->logError("pipe failed"); handleException(); } const int pid = fork(); if (pid < 0) { - logg->logError(__FILE__, __LINE__, "fork failed"); + logg->logError("fork failed"); handleException(); } if (pid == 0) { @@ -163,7 +163,7 @@ void *commandThread(void *) { close(pipefd[1]); const ssize_t bytes = read(pipefd[0], buf, sizeof(buf)); if (bytes > 0) { - logg->logError(__FILE__, __LINE__, buf); + logg->logError("%s", buf); handleException(); } close(pipefd[0]); diff --git a/tools/gator/daemon/Command.h b/tools/gator/daemon/Command.h index 17244b7aaebc..2838adcec661 100644 --- a/tools/gator/daemon/Command.h +++ b/tools/gator/daemon/Command.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2014. All rights reserved. + * Copyright (C) ARM Limited 2014-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/Config.h b/tools/gator/daemon/Config.h index bee383a1c797..eb31556e6426 100644 --- a/tools/gator/daemon/Config.h +++ b/tools/gator/daemon/Config.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/ConfigurationXML.cpp b/tools/gator/daemon/ConfigurationXML.cpp index 6590dd389196..be224a4f2b1f 100644 --- a/tools/gator/daemon/ConfigurationXML.cpp +++ b/tools/gator/daemon/ConfigurationXML.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -106,7 +106,7 @@ void ConfigurationXML::validate(void) { const Counter & counter = gSessionData->mCounters[i]; if (counter.isEnabled()) { if (strcmp(counter.getType(), "") == 0) { - logg->logError(__FILE__, __LINE__, "Invalid required attribute in configuration.xml:\n counter=\"%s\"\n event=%d\n", counter.getType(), counter.getEvent()); + logg->logError("Invalid required attribute in configuration.xml:\n counter=\"%s\"\n event=%d\n", counter.getType(), counter.getEvent()); handleException(); } @@ -116,7 +116,7 @@ void ConfigurationXML::validate(void) { if (counter2.isEnabled()) { // check if the types are the same if (strcmp(counter.getType(), counter2.getType()) == 0) { - logg->logError(__FILE__, __LINE__, "Duplicate performance counter type in configuration.xml: %s", counter.getType()); + logg->logError("Duplicate performance counter type in configuration.xml: %s", counter.getType()); handleException(); } } @@ -169,7 +169,7 @@ void ConfigurationXML::configurationTag(mxml_node_t *node) { for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) { if (driver->claimCounter(counter)) { if (counter.getDriver() != NULL) { - logg->logError(__FILE__, __LINE__, "More than one driver has claimed %s:%i", counter.getType(), counter.getEvent()); + logg->logError("More than one driver has claimed %s:%i", counter.getType(), counter.getEvent()); handleException(); } counter.setDriver(driver); @@ -210,7 +210,7 @@ void ConfigurationXML::remove() { getPath(path); if (::remove(path) != 0) { - logg->logError(__FILE__, __LINE__, "Invalid configuration.xml file detected and unable to delete it. To resolve, delete configuration.xml on disk"); + logg->logError("Invalid configuration.xml file detected and unable to delete it. To resolve, delete configuration.xml on disk"); handleException(); } logg->logMessage("Invalid configuration.xml file detected and removed"); diff --git a/tools/gator/daemon/ConfigurationXML.h b/tools/gator/daemon/ConfigurationXML.h index efa415e508b6..a986ce99381b 100644 --- a/tools/gator/daemon/ConfigurationXML.h +++ b/tools/gator/daemon/ConfigurationXML.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/Counter.h b/tools/gator/daemon/Counter.h index 5202aa046362..a4c22f571342 100644 --- a/tools/gator/daemon/Counter.h +++ b/tools/gator/daemon/Counter.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/DiskIODriver.cpp b/tools/gator/daemon/DiskIODriver.cpp index 5deb0f375f3a..af62bb9a95bd 100644 --- a/tools/gator/daemon/DiskIODriver.cpp +++ b/tools/gator/daemon/DiskIODriver.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -67,7 +67,7 @@ void DiskIODriver::doRead() { } if (!mBuf.read("/proc/diskstats")) { - logg->logError(__FILE__, __LINE__, "Unable to read /proc/diskstats"); + logg->logError("Unable to read /proc/diskstats"); handleException(); } @@ -76,9 +76,9 @@ void DiskIODriver::doRead() { char *lastName = NULL; int lastNameLen = -1; - char *start = mBuf.getBuf(); - while (*start != '\0') { - char *end = strchr(start, '\n'); + char *line = mBuf.getBuf(); + while (*line != '\0') { + char *end = strchr(line, '\n'); if (end != NULL) { *end = '\0'; } @@ -87,15 +87,15 @@ void DiskIODriver::doRead() { int nameEnd = -1; int64_t readBytes = -1; int64_t writeBytes = -1; - const int count = sscanf(start, "%*d %*d %n%*s%n %*u %*u %" SCNu64 " %*u %*u %*u %" SCNu64, &nameStart, &nameEnd, &readBytes, &writeBytes); + const int count = sscanf(line, "%*d %*d %n%*s%n %*u %*u %" SCNu64 " %*u %*u %*u %" SCNu64, &nameStart, &nameEnd, &readBytes, &writeBytes); if (count != 2) { - logg->logError(__FILE__, __LINE__, "Unable to parse /proc/diskstats"); + logg->logError("Unable to parse /proc/diskstats"); handleException(); } // Skip partitions which are identified if the name is a substring of the last non-partition - if ((lastName == NULL) || (strncmp(lastName, start + nameStart, lastNameLen) != 0)) { - lastName = start + nameStart; + if ((lastName == NULL) || (strncmp(lastName, line + nameStart, lastNameLen) != 0)) { + lastName = line + nameStart; lastNameLen = nameEnd - nameStart; mReadBytes += readBytes; mWriteBytes += writeBytes; @@ -104,7 +104,7 @@ void DiskIODriver::doRead() { if (end == NULL) { break; } - start = end + 1; + line = end + 1; } } diff --git a/tools/gator/daemon/DiskIODriver.h b/tools/gator/daemon/DiskIODriver.h index d0db18c77d04..6ecda5afc25a 100644 --- a/tools/gator/daemon/DiskIODriver.h +++ b/tools/gator/daemon/DiskIODriver.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/Driver.cpp b/tools/gator/daemon/Driver.cpp index 275da31c7a0d..72c731424bde 100644 --- a/tools/gator/daemon/Driver.cpp +++ b/tools/gator/daemon/Driver.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/Driver.h b/tools/gator/daemon/Driver.h index 72870e3dbca1..19ec12775a39 100644 --- a/tools/gator/daemon/Driver.h +++ b/tools/gator/daemon/Driver.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/DriverSource.cpp b/tools/gator/daemon/DriverSource.cpp index 7f299b646952..34920cee92fb 100644 --- a/tools/gator/daemon/DriverSource.cpp +++ b/tools/gator/daemon/DriverSource.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -32,7 +32,7 @@ DriverSource::DriverSource(sem_t *senderSem, sem_t *startProfile) : mBuffer(NULL mBuffer = new Buffer(0, FRAME_PERF_ATTRS, 4*1024*1024, senderSem); if (readIntDriver("/dev/gator/version", &driver_version) == -1) { - logg->logError(__FILE__, __LINE__, "Error reading gator driver version"); + logg->logError("Error reading gator driver version"); handleException(); } @@ -40,7 +40,7 @@ DriverSource::DriverSource(sem_t *senderSem, sem_t *startProfile) : mBuffer(NULL if (driver_version != PROTOCOL_VERSION) { if ((driver_version > PROTOCOL_DEV) || (PROTOCOL_VERSION > PROTOCOL_DEV)) { // One of the mismatched versions is development version - logg->logError(__FILE__, __LINE__, + logg->logError( "DEVELOPMENT BUILD MISMATCH: gator driver version \"%d\" is not in sync with gator daemon version \"%d\".\n" ">> The following must be synchronized from engineering repository:\n" ">> * gator driver\n" @@ -49,7 +49,7 @@ DriverSource::DriverSource(sem_t *senderSem, sem_t *startProfile) : mBuffer(NULL handleException(); } else { // Release version mismatch - logg->logError(__FILE__, __LINE__, + logg->logError( "gator driver version \"%d\" is different than gator daemon version \"%d\".\n" ">> Please upgrade the driver and daemon to the latest versions.", driver_version, PROTOCOL_VERSION); handleException(); @@ -58,7 +58,7 @@ DriverSource::DriverSource(sem_t *senderSem, sem_t *startProfile) : mBuffer(NULL int enable = -1; if (readIntDriver("/dev/gator/enable", &enable) != 0 || enable != 0) { - logg->logError(__FILE__, __LINE__, "Driver already enabled, possibly a session is already in progress."); + logg->logError("Driver already enabled, possibly a session is already in progress."); handleException(); } @@ -68,7 +68,7 @@ DriverSource::DriverSource(sem_t *senderSem, sem_t *startProfile) : mBuffer(NULL } if (readIntDriver("/dev/gator/buffer_size", &mBufferSize) || mBufferSize <= 0) { - logg->logError(__FILE__, __LINE__, "Unable to read the driver buffer size"); + logg->logError("Unable to read the driver buffer size"); handleException(); } } @@ -99,10 +99,11 @@ void DriverSource::bootstrapThread() { DynBuf printb; DynBuf b1; DynBuf b2; - const uint64_t currTime = getTime(); + // MonotonicStarted may not be not assigned yet + const uint64_t currTime = 0;//getTime() - gSessionData->mMonotonicStarted; if (!readProcComms(currTime, mBuffer, &printb, &b1, &b2)) { - logg->logError(__FILE__, __LINE__, "readProcComms failed"); + logg->logError("readProcComms failed"); handleException(); } @@ -124,33 +125,33 @@ void DriverSource::run() { // Set the maximum backtrace depth if (writeReadDriver("/dev/gator/backtrace_depth", &gSessionData->mBacktraceDepth)) { - logg->logError(__FILE__, __LINE__, "Unable to set the driver backtrace depth"); + logg->logError("Unable to set the driver backtrace depth"); handleException(); } // open the buffer which calls userspace_buffer_open() in the driver mBufferFD = open("/dev/gator/buffer", O_RDONLY | O_CLOEXEC); if (mBufferFD < 0) { - 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."); + logg->logError("The gator driver did not set up properly. Please view the linux console or dmesg log for more information on the failure."); handleException(); } // set the tick rate of the profiling timer if (writeReadDriver("/dev/gator/tick", &gSessionData->mSampleRate) != 0) { - logg->logError(__FILE__, __LINE__, "Unable to set the driver tick"); + logg->logError("Unable to set the driver tick"); handleException(); } // notify the kernel of the response type int response_type = gSessionData->mLocalCapture ? 0 : RESPONSE_APC_DATA; if (writeDriver("/dev/gator/response_type", response_type)) { - logg->logError(__FILE__, __LINE__, "Unable to write the response type"); + logg->logError("Unable to write the response type"); handleException(); } // Set the live rate if (writeReadDriver("/dev/gator/live_rate", &gSessionData->mLiveRate)) { - logg->logError(__FILE__, __LINE__, "Unable to set the driver live rate"); + logg->logError("Unable to set the driver live rate"); handleException(); } @@ -158,7 +159,7 @@ void DriverSource::run() { // This command makes the driver start profiling by calling gator_op_start() in the driver if (writeDriver("/dev/gator/enable", "1") != 0) { - 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."); + logg->logError("The gator driver did not start properly. Please view the linux console or dmesg log for more information on the failure."); handleException(); } @@ -168,7 +169,7 @@ void DriverSource::run() { pthread_t bootstrapThreadID; if (pthread_create(&bootstrapThreadID, NULL, bootstrapThreadStatic, this) != 0) { - logg->logError(__FILE__, __LINE__, "Unable to start the gator_bootstrap thread"); + logg->logError("Unable to start the gator_bootstrap thread"); handleException(); } @@ -190,7 +191,7 @@ void DriverSource::run() { // In one shot mode, stop collection once all the buffers are filled if (gSessionData->mOneShot && gSessionData->mSessionIsActive) { if (bytesCollected == -1 || mFifo->willFill(bytesCollected)) { - logg->logMessage("One shot"); + logg->logMessage("One shot (gator.ko)"); child->endSession(); } } diff --git a/tools/gator/daemon/DriverSource.h b/tools/gator/daemon/DriverSource.h index ec27b0815bbf..32d983d6d036 100644 --- a/tools/gator/daemon/DriverSource.h +++ b/tools/gator/daemon/DriverSource.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/DynBuf.cpp b/tools/gator/daemon/DynBuf.cpp index df20713ad63c..690cbcb94293 100644 --- a/tools/gator/daemon/DynBuf.cpp +++ b/tools/gator/daemon/DynBuf.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -42,7 +42,7 @@ bool DynBuf::read(const char *const path) { const int fd = open(path, O_RDONLY | O_CLOEXEC); if (fd < 0) { - logg->logMessage("%s(%s:%i): open failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("open failed"); return false; } @@ -52,14 +52,14 @@ bool DynBuf::read(const char *const path) { const size_t minCapacity = length + MIN_BUFFER_FREE + 1; if (capacity < minCapacity) { if (resize(minCapacity) != 0) { - logg->logMessage("%s(%s:%i): DynBuf::resize failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("DynBuf::resize failed"); goto fail; } } const ssize_t bytes = ::read(fd, buf + length, capacity - length - 1); if (bytes < 0) { - logg->logMessage("%s(%s:%i): read failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("read failed"); goto fail; } else if (bytes == 0) { break; @@ -105,7 +105,7 @@ bool DynBuf::printf(const char *format, ...) { if (capacity <= 0) { if (resize(2 * MIN_BUFFER_FREE) != 0) { - logg->logMessage("%s(%s:%i): DynBuf::resize failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("DynBuf::resize failed"); return false; } } @@ -114,13 +114,13 @@ bool DynBuf::printf(const char *format, ...) { int bytes = vsnprintf(buf, capacity, format, ap); va_end(ap); if (bytes < 0) { - logg->logMessage("%s(%s:%i): fsnprintf failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("fsnprintf failed"); return false; } if (static_cast(bytes) > capacity) { if (resize(bytes + 1) != 0) { - logg->logMessage("%s(%s:%i): DynBuf::resize failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("DynBuf::resize failed"); return false; } @@ -128,7 +128,7 @@ bool DynBuf::printf(const char *format, ...) { bytes = vsnprintf(buf, capacity, format, ap); va_end(ap); if (bytes < 0) { - logg->logMessage("%s(%s:%i): fsnprintf failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("fsnprintf failed"); return false; } } diff --git a/tools/gator/daemon/DynBuf.h b/tools/gator/daemon/DynBuf.h index 2f4554ab2e49..da83cd65ca3e 100644 --- a/tools/gator/daemon/DynBuf.h +++ b/tools/gator/daemon/DynBuf.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/EventsXML.cpp b/tools/gator/daemon/EventsXML.cpp index d905bbabe988..cec08d5a6fff 100644 --- a/tools/gator/daemon/EventsXML.cpp +++ b/tools/gator/daemon/EventsXML.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -13,10 +13,35 @@ #include "OlyUtility.h" #include "SessionData.h" +class XMLList { +public: + XMLList(XMLList *const prev, mxml_node_t *const node) : mPrev(prev), mNode(node) {} + + XMLList *getPrev() { return mPrev; } + mxml_node_t *getNode() const { return mNode; } + void setNode(mxml_node_t *const node) { mNode = node; } + + static void free(XMLList *list) { + while (list != NULL) { + XMLList *prev = list->getPrev(); + delete list; + list = prev; + } + } + +private: + XMLList *const mPrev; + mxml_node_t *mNode; + + // Intentionally unimplemented + XMLList(const XMLList &); + XMLList &operator=(const XMLList &); +}; + mxml_node_t *EventsXML::getTree() { #include "events_xml.h" // defines and initializes char events_xml[] and int events_xml_len char path[PATH_MAX]; - mxml_node_t *xml; + mxml_node_t *xml = NULL; FILE *fl; // Avoid unused variable warning @@ -25,19 +50,147 @@ mxml_node_t *EventsXML::getTree() { // Load the provided or default events xml if (gSessionData->mEventsXMLPath) { strncpy(path, gSessionData->mEventsXMLPath, PATH_MAX); - } else { - util->getApplicationFullPath(path, PATH_MAX); - strncat(path, "events.xml", PATH_MAX - strlen(path) - 1); + fl = fopen(path, "r"); + if (fl) { + xml = mxmlLoadFile(NULL, fl, MXML_NO_CALLBACK); + fclose(fl); + } } - fl = fopen(path, "r"); - if (fl) { - xml = mxmlLoadFile(NULL, fl, MXML_NO_CALLBACK); - fclose(fl); - } else { + if (xml == NULL) { logg->logMessage("Unable to locate events.xml, using default"); xml = mxmlLoadString(NULL, (const char *)events_xml, MXML_NO_CALLBACK); } + // Append additional events XML + if (gSessionData->mEventsXMLAppend) { + fl = fopen(gSessionData->mEventsXMLAppend, "r"); + if (fl == NULL) { + logg->logError("Unable to open additional events XML %s", gSessionData->mEventsXMLAppend); + handleException(); + } + mxml_node_t *append = mxmlLoadFile(NULL, fl, MXML_NO_CALLBACK); + fclose(fl); + + mxml_node_t *events = mxmlFindElement(xml, xml, "events", NULL, NULL, MXML_DESCEND); + if (!events) { + logg->logError("Unable to find node in the events.xml, please ensure the first two lines of events XML starts with:\n" + "\n" + ""); + handleException(); + } + + XMLList *categoryList = NULL; + XMLList *eventList = NULL; + { + // Make list of all categories in xml + mxml_node_t *node = xml; + while (true) { + node = mxmlFindElement(node, xml, "category", NULL, NULL, MXML_DESCEND); + if (node == NULL) { + break; + } + categoryList = new XMLList(categoryList, node); + } + + // Make list of all events in xml + node = xml; + while (true) { + node = mxmlFindElement(node, xml, "event", NULL, NULL, MXML_DESCEND); + if (node == NULL) { + break; + } + eventList = new XMLList(eventList, node); + } + } + + // Handle events + for (mxml_node_t *node = mxmlFindElement(append, append, "event", NULL, NULL, MXML_DESCEND), + *next = mxmlFindElement(node, append, "event", NULL, NULL, MXML_DESCEND); + node != NULL; + node = next, next = mxmlFindElement(node, append, "event", NULL, NULL, MXML_DESCEND)) { + const char *const category = mxmlElementGetAttr(mxmlGetParent(node), "name"); + const char *const title = mxmlElementGetAttr(node, "title"); + const char *const name = mxmlElementGetAttr(node, "name"); + if (category == NULL || title == NULL || name == NULL) { + logg->logError("Not all event XML nodes have the required title and name and parent name attributes"); + handleException(); + } + + // Replace any duplicate events + for (XMLList *event = eventList; event != NULL; event = event->getPrev()) { + const char *const category2 = mxmlElementGetAttr(mxmlGetParent(event->getNode()), "name"); + const char *const title2 = mxmlElementGetAttr(event->getNode(), "title"); + const char *const name2 = mxmlElementGetAttr(event->getNode(), "name"); + if (category2 == NULL || title2 == NULL || name2 == NULL) { + logg->logError("Not all event XML nodes have the required title and name and parent name attributes"); + handleException(); + } + + if (strcmp(category, category2) == 0 && strcmp(title, title2) == 0 && strcmp(name, name2) == 0) { + logg->logMessage("Replacing counter %s %s: %s", category, title, name); + mxml_node_t *parent = mxmlGetParent(event->getNode()); + mxmlDelete(event->getNode()); + mxmlAdd(parent, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, node); + event->setNode(node); + break; + } + } + } + + // Handle categories + for (mxml_node_t *node = strcmp(mxmlGetElement(append), "category") == 0 ? append : mxmlFindElement(append, append, "category", NULL, NULL, MXML_DESCEND), + *next = mxmlFindElement(node, append, "category", NULL, NULL, MXML_DESCEND); + node != NULL; + node = next, next = mxmlFindElement(node, append, "category", NULL, NULL, MXML_DESCEND)) { + // After replacing duplicate events, a category may be empty + if (mxmlGetFirstChild(node) == NULL) { + continue; + } + + const char *const name = mxmlElementGetAttr(node, "name"); + if (name == NULL) { + logg->logError("Not all event XML categories have the required name attribute"); + handleException(); + } + + // Merge identically named categories + bool merged = false; + for (XMLList *category = categoryList; category != NULL; category = category->getPrev()) { + const char *const name2 = mxmlElementGetAttr(category->getNode(), "name"); + if (name2 == NULL) { + logg->logError("Not all event XML categories have the required name attribute"); + handleException(); + } + + if (strcmp(name, name2) == 0) { + logg->logMessage("Merging category %s", name); + while (true) { + mxml_node_t *child = mxmlGetFirstChild(node); + if (child == NULL) { + break; + } + mxmlAdd(category->getNode(), MXML_ADD_AFTER, mxmlGetLastChild(category->getNode()), child); + } + merged = true; + break; + } + } + + if (merged) { + continue; + } + + // Add new categories + logg->logMessage("Appending category %s", name); + mxmlAdd(events, MXML_ADD_AFTER, mxmlGetLastChild(events), node); + } + + XMLList::free(eventList); + XMLList::free(categoryList); + + mxmlDelete(append); + } + return xml; } @@ -47,7 +200,9 @@ char *EventsXML::getXML() { // Add dynamic events from the drivers mxml_node_t *events = mxmlFindElement(xml, xml, "events", NULL, NULL, MXML_DESCEND); if (!events) { - logg->logError(__FILE__, __LINE__, "Unable to find node in the events.xml"); + logg->logError("Unable to find node in the events.xml, please ensure the first two lines of events XML are:\n" + "\n" + ""); handleException(); } for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) { @@ -68,7 +223,7 @@ void EventsXML::write(const char *path) { char *buf = getXML(); if (util->writeToDisk(file, buf) < 0) { - logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify the path.", file); + logg->logError("Error writing %s\nPlease verify the path.", file); handleException(); } diff --git a/tools/gator/daemon/EventsXML.h b/tools/gator/daemon/EventsXML.h index ff7a02fd3c78..2b38fa4364e0 100644 --- a/tools/gator/daemon/EventsXML.h +++ b/tools/gator/daemon/EventsXML.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -13,9 +13,16 @@ class EventsXML { public: + EventsXML() {} + mxml_node_t *getTree(); char *getXML(); void write(const char* path); + +private: + // Intentionally unimplemented + EventsXML(const EventsXML &); + EventsXML &operator=(const EventsXML &); }; #endif // EVENTS_XML diff --git a/tools/gator/daemon/ExternalSource.cpp b/tools/gator/daemon/ExternalSource.cpp index 8f5e6b684c53..8d71b6de3d5e 100644 --- a/tools/gator/daemon/ExternalSource.cpp +++ b/tools/gator/daemon/ExternalSource.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -12,10 +12,14 @@ #include #include +#include "Child.h" #include "Logging.h" #include "OlySocket.h" #include "SessionData.h" +extern Child *child; + +static const char STREAMLINE_ANNOTATE[] = "\0streamline-annotate"; static const char MALI_VIDEO[] = "\0mali-video"; static const char MALI_VIDEO_STARTUP[] = "\0mali-video-startup"; static const char MALI_VIDEO_V1[] = "MALI_VIDEO 1\n"; @@ -40,7 +44,7 @@ static bool setNonblock(const int fd) { return true; } -ExternalSource::ExternalSource(sem_t *senderSem) : mBuffer(0, FRAME_EXTERNAL, 128*1024, senderSem), mMonitor(), mMveStartupUds(MALI_VIDEO_STARTUP, sizeof(MALI_VIDEO_STARTUP)), mMaliStartupUds(MALI_GRAPHICS_STARTUP, sizeof(MALI_GRAPHICS_STARTUP)), mAnnotate(8083), mInterruptFd(-1), mMaliUds(-1), mMveUds(-1) { +ExternalSource::ExternalSource(sem_t *senderSem) : mBuffer(0, FRAME_EXTERNAL, 128*1024, senderSem), mMonitor(), mMveStartupUds(MALI_VIDEO_STARTUP, sizeof(MALI_VIDEO_STARTUP)), mMaliStartupUds(MALI_GRAPHICS_STARTUP, sizeof(MALI_GRAPHICS_STARTUP)), mAnnotate(8083), mAnnotateUds(STREAMLINE_ANNOTATE, sizeof(STREAMLINE_ANNOTATE), true), mInterruptFd(-1), mMaliUds(-1), mMveUds(-1) { sem_init(&mBufferSem, 0, 0); } @@ -49,18 +53,22 @@ ExternalSource::~ExternalSource() { void ExternalSource::waitFor(const int bytes) { while (mBuffer.bytesAvailable() <= bytes) { + if (gSessionData->mOneShot && gSessionData->mSessionIsActive) { + logg->logMessage("One shot (external)"); + child->endSession(); + } sem_wait(&mBufferSem); } } void ExternalSource::configureConnection(const int fd, const char *const handshake, size_t size) { if (!setNonblock(fd)) { - logg->logError(__FILE__, __LINE__, "Unable to set nonblock on fh"); + logg->logError("Unable to set nonblock on fh"); handleException(); } if (!mMonitor.add(fd)) { - logg->logError(__FILE__, __LINE__, "Unable to add fh to monitor"); + logg->logError("Unable to add fh to monitor"); handleException(); } @@ -68,7 +76,7 @@ void ExternalSource::configureConnection(const int fd, const char *const handsha waitFor(Buffer::MAXSIZE_PACK32 + size - 1); mBuffer.packInt(fd); mBuffer.writeBytes(handshake, size - 1); - mBuffer.commit(1); + mBuffer.commit(1, true); } bool ExternalSource::connectMali() { @@ -106,6 +114,7 @@ bool ExternalSource::prepare() { !setNonblock(mMveStartupUds.getFd()) || !mMonitor.add(mMveStartupUds.getFd()) || !setNonblock(mMaliStartupUds.getFd()) || !mMonitor.add(mMaliStartupUds.getFd()) || !setNonblock(mAnnotate.getFd()) || !mMonitor.add(mAnnotate.getFd()) || + !setNonblock(mAnnotateUds.getFd()) || !mMonitor.add(mAnnotateUds.getFd()) || false) { return false; } @@ -122,18 +131,21 @@ void ExternalSource::run() { prctl(PR_SET_NAME, (unsigned long)&"gatord-external", 0, 0, 0); if (pipe_cloexec(pipefd) != 0) { - logg->logError(__FILE__, __LINE__, "pipe failed"); + logg->logError("pipe failed"); handleException(); } mInterruptFd = pipefd[1]; if (!mMonitor.add(pipefd[0])) { - logg->logError(__FILE__, __LINE__, "Monitor::add failed"); + logg->logError("Monitor::add failed"); handleException(); } // Notify annotate clients to retry connecting to gatord - gSessionData->annotateListener.signal(); + uint64_t val = 1; + if (::write(gSessionData->mAnnotateStart, &val, sizeof(val)) != sizeof(val)) { + logg->logMessage("Writing to annotate pipe failed"); + } while (gSessionData->mSessionIsActive) { struct epoll_event events[16]; @@ -141,11 +153,11 @@ void ExternalSource::run() { while (sem_trywait(&mBufferSem) == 0); int ready = mMonitor.wait(events, ARRAY_LENGTH(events), -1); if (ready < 0) { - logg->logError(__FILE__, __LINE__, "Monitor::wait failed"); + logg->logError("Monitor::wait failed"); handleException(); } - const uint64_t currTime = getTime(); + const uint64_t currTime = getTime() - gSessionData->mMonotonicStarted; for (int i = 0; i < ready; ++i) { const int fd = events[i].data.fd; @@ -155,7 +167,7 @@ void ExternalSource::run() { // Don't read from this connection, establish a new connection to Mali-V500 close(client); if (!connectMve()) { - logg->logError(__FILE__, __LINE__, "Unable to configure incoming Mali video connection"); + logg->logError("Unable to configure incoming Mali video connection"); handleException(); } } else if (fd == mMaliStartupUds.getFd()) { @@ -164,13 +176,19 @@ void ExternalSource::run() { // Don't read from this connection, establish a new connection to Mali Graphics close(client); if (!connectMali()) { - logg->logError(__FILE__, __LINE__, "Unable to configure incoming Mali graphics connection"); + logg->logError("Unable to configure incoming Mali graphics connection"); handleException(); } } else if (fd == mAnnotate.getFd()) { int client = mAnnotate.acceptConnection(); if (!setNonblock(client) || !mMonitor.add(client)) { - logg->logError(__FILE__, __LINE__, "Unable to set socket options on incoming annotation connection"); + logg->logError("Unable to set socket options on incoming annotation connection"); + handleException(); + } + } else if (fd == mAnnotateUds.getFd()) { + int client = mAnnotateUds.acceptConnection(); + if (!setNonblock(client) || !mMonitor.add(client)) { + logg->logError("Unable to set socket options on incoming annotation connection"); handleException(); } } else if (fd == pipefd[0]) { @@ -190,28 +208,29 @@ void ExternalSource::run() { if (bytes < 0) { if (errno == EAGAIN) { // Nothing left to read - mBuffer.commit(currTime); + mBuffer.commit(currTime, true); break; } // Something else failed, close the socket - mBuffer.commit(currTime); + mBuffer.commit(currTime, true); mBuffer.packInt(-1); mBuffer.packInt(fd); - mBuffer.commit(currTime); + // Here and other commits, always force-flush the buffer as this frame don't work like others + mBuffer.commit(currTime, true); close(fd); break; } else if (bytes == 0) { // The other side is closed - mBuffer.commit(currTime); + mBuffer.commit(currTime, true); mBuffer.packInt(-1); mBuffer.packInt(fd); - mBuffer.commit(currTime); + mBuffer.commit(currTime, true); close(fd); break; } mBuffer.advanceWrite(bytes); - mBuffer.commit(currTime); + mBuffer.commit(currTime, true); // Short reads also mean nothing is left to read if (bytes < contiguous) { @@ -238,7 +257,7 @@ void ExternalSource::interrupt() { int8_t c = 0; // Write to the pipe to wake the monitor which will cause mSessionIsActive to be reread if (::write(mInterruptFd, &c, sizeof(c)) != sizeof(c)) { - logg->logError(__FILE__, __LINE__, "write failed"); + logg->logError("write failed"); handleException(); } } diff --git a/tools/gator/daemon/ExternalSource.h b/tools/gator/daemon/ExternalSource.h index 919e75e8a41a..25ae7cd4c4ab 100644 --- a/tools/gator/daemon/ExternalSource.h +++ b/tools/gator/daemon/ExternalSource.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -41,6 +41,7 @@ private: OlyServerSocket mMveStartupUds; OlyServerSocket mMaliStartupUds; OlyServerSocket mAnnotate; + OlyServerSocket mAnnotateUds; int mInterruptFd; int mMaliUds; int mMveUds; diff --git a/tools/gator/daemon/FSDriver.cpp b/tools/gator/daemon/FSDriver.cpp index dd8eb804dc99..afac9dfb6761 100644 --- a/tools/gator/daemon/FSDriver.cpp +++ b/tools/gator/daemon/FSDriver.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2014. All rights reserved. + * Copyright (C) ARM Limited 2014-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -42,7 +42,7 @@ FSCounter::FSCounter(DriverCounter *next, char *name, char *path, const char *re if (result != 0) { char buf[128]; regerror(result, &mReg, buf, sizeof(buf)); - logg->logError(__FILE__, __LINE__, "Invalid regex '%s': %s", regex, buf); + logg->logError("Invalid regex '%s': %s", regex, buf); handleException(); } } @@ -79,21 +79,19 @@ int64_t FSCounter::read() { regmatch_t match[2]; int result = regexec(&mReg, buf, 2, match, 0); if (result != 0) { - regerror(result, &mReg, buf, sizeof(buf)); - logg->logError(__FILE__, __LINE__, "Parsing %s failed: %s", mPath, buf); - handleException(); + // No match + return 0; } if (match[1].rm_so < 0) { - logg->logError(__FILE__, __LINE__, "Parsing %s failed", mPath); - handleException(); - } - - errno = 0; - value = strtoll(buf + match[1].rm_so, NULL, 0); - if (errno != 0) { - logg->logError(__FILE__, __LINE__, "Parsing %s failed: %s", mPath, strerror(errno)); - handleException(); + value = 1; + } else { + errno = 0; + value = strtoll(buf + match[1].rm_so, NULL, 0); + if (errno != 0) { + logg->logError("Parsing %s failed: %s", mPath, strerror(errno)); + handleException(); + } } } else { if (DriverSource::readInt64Driver(mPath, &value) != 0) { @@ -103,7 +101,7 @@ int64_t FSCounter::read() { return value; fail: - logg->logError(__FILE__, __LINE__, "Unable to read %s", mPath); + logg->logError("Unable to read %s", mPath); handleException(); } @@ -126,7 +124,7 @@ void FSDriver::readEvents(mxml_node_t *const xml) { } if (counter[0] == '/') { - logg->logError(__FILE__, __LINE__, "Old style filesystem counter (%s) detected, please create a new unique counter value and move the filename into the path attribute, see events-Filesystem.xml for examples", counter); + logg->logError("Old style filesystem counter (%s) detected, please create a new unique counter value and move the filename into the path attribute, see events-Filesystem.xml for examples", counter); handleException(); } @@ -136,7 +134,7 @@ void FSDriver::readEvents(mxml_node_t *const xml) { const char *path = mxmlElementGetAttr(node, "path"); if (path == NULL) { - logg->logError(__FILE__, __LINE__, "The filesystem counter %s is missing the required path attribute", counter); + logg->logError("The filesystem counter %s is missing the required path attribute", counter); handleException(); } const char *regex = mxmlElementGetAttr(node, "regex"); diff --git a/tools/gator/daemon/FSDriver.h b/tools/gator/daemon/FSDriver.h index a7dc8b4df9dd..63a4e90a2b46 100644 --- a/tools/gator/daemon/FSDriver.h +++ b/tools/gator/daemon/FSDriver.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2014. All rights reserved. + * Copyright (C) ARM Limited 2014-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/Fifo.cpp b/tools/gator/daemon/Fifo.cpp index 41275fd287b8..8d3b9ff8d385 100644 --- a/tools/gator/daemon/Fifo.cpp +++ b/tools/gator/daemon/Fifo.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -24,12 +24,12 @@ Fifo::Fifo(int singleBufferSize, int bufferSize, sem_t* readerSem) { mEnd = false; if (mBuffer == NULL) { - logg->logError(__FILE__, __LINE__, "failed to allocate %d bytes", bufferSize + singleBufferSize); + logg->logError("failed to allocate %d bytes", bufferSize + singleBufferSize); handleException(); } if (sem_init(&mWaitForSpaceSem, 0, 0)) { - logg->logError(__FILE__, __LINE__, "sem_init() failed"); + logg->logError("sem_init() failed"); handleException(); } } diff --git a/tools/gator/daemon/Fifo.h b/tools/gator/daemon/Fifo.h index 21c8d8580391..01fa11b2f2c4 100644 --- a/tools/gator/daemon/Fifo.h +++ b/tools/gator/daemon/Fifo.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/FtraceDriver.cpp b/tools/gator/daemon/FtraceDriver.cpp index b156f1c0b8b4..98bd0a5d9eec 100644 --- a/tools/gator/daemon/FtraceDriver.cpp +++ b/tools/gator/daemon/FtraceDriver.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2014. All rights reserved. + * Copyright (C) ARM Limited 2014-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -9,56 +9,80 @@ #include "FtraceDriver.h" #include +#include +#include "DriverSource.h" #include "Logging.h" +#include "Setup.h" class FtraceCounter : public DriverCounter { public: - FtraceCounter(DriverCounter *next, char *name, const char *regex); + FtraceCounter(DriverCounter *next, char *name, const char *regex, const char *enable); ~FtraceCounter(); + void prepare(); int read(const char *const line, int64_t *values); + void stop(); private: - regex_t reg; + regex_t mReg; + char *const mEnable; + int mWasEnabled; // Intentionally unimplemented FtraceCounter(const FtraceCounter &); FtraceCounter &operator=(const FtraceCounter &); }; -FtraceCounter::FtraceCounter(DriverCounter *next, char *name, const char *regex) : DriverCounter(next, name) { - int result = regcomp(®, regex, REG_EXTENDED); +FtraceCounter::FtraceCounter(DriverCounter *next, char *name, const char *regex, const char *enable) : DriverCounter(next, name), mEnable(enable == NULL ? NULL : strdup(enable)) { + int result = regcomp(&mReg, regex, REG_EXTENDED); if (result != 0) { char buf[128]; - regerror(result, ®, buf, sizeof(buf)); - logg->logError(__FILE__, __LINE__, "Invalid regex '%s': %s", regex, buf); + regerror(result, &mReg, buf, sizeof(buf)); + logg->logError("Invalid regex '%s': %s", regex, buf); handleException(); } } FtraceCounter::~FtraceCounter() { - regfree(®); + regfree(&mReg); + if (mEnable != NULL) { + free(mEnable); + } +} + +void FtraceCounter::prepare() { + if (mEnable == NULL) { + return; + } + + char buf[1<<10]; + snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%s/enable", mEnable); + if ((DriverSource::readIntDriver(buf, &mWasEnabled) != 0) || + (DriverSource::writeDriver(buf, 1) != 0)) { + logg->logError("Unable to read or write to %s", buf); + handleException(); + } } int FtraceCounter::read(const char *const line, int64_t *values) { regmatch_t match[2]; - int result = regexec(®, line, 2, match, 0); + int result = regexec(&mReg, line, 2, match, 0); if (result != 0) { // No match return 0; } + int64_t value; if (match[1].rm_so < 0) { - logg->logError(__FILE__, __LINE__, "Parsing %s failed", getName()); - handleException(); - } - - errno = 0; - int64_t value = strtoll(line + match[1].rm_so, NULL, 0); - if (errno != 0) { - logg->logError(__FILE__, __LINE__, "Parsing %s failed: %s", getName(), strerror(errno)); - handleException(); + value = 1; + } else { + errno = 0; + value = strtoll(line + match[1].rm_so, NULL, 0); + if (errno != 0) { + logg->logError("Parsing %s failed: %s", getName(), strerror(errno)); + handleException(); + } } values[0] = getKey(); @@ -67,6 +91,16 @@ int FtraceCounter::read(const char *const line, int64_t *values) { return 1; } +void FtraceCounter::stop() { + if (mEnable == NULL) { + return; + } + + char buf[1<<10]; + snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%s/enable", mEnable); + DriverSource::writeDriver(buf, mWasEnabled); +} + FtraceDriver::FtraceDriver() : mValues(NULL) { } @@ -75,6 +109,19 @@ FtraceDriver::~FtraceDriver() { } void FtraceDriver::readEvents(mxml_node_t *const xml) { + // Check the kernel version + int release[3]; + if (!getLinuxVersion(release)) { + logg->logError("getLinuxVersion failed"); + handleException(); + } + + // The perf clock was added in 3.10 + if (KERNEL_VERSION(release[0], release[1], release[2]) < KERNEL_VERSION(3, 10, 0)) { + logg->logMessage("Unsupported kernel version, to use ftrace please upgrade to Linux 3.10 or later"); + return; + } + mxml_node_t *node = xml; int count = 0; while (true) { @@ -93,16 +140,37 @@ void FtraceDriver::readEvents(mxml_node_t *const xml) { const char *regex = mxmlElementGetAttr(node, "regex"); if (regex == NULL) { - logg->logError(__FILE__, __LINE__, "The regex counter %s is missing the required regex attribute", counter); + logg->logError("The regex counter %s is missing the required regex attribute", counter); handleException(); } - setCounters(new FtraceCounter(getCounters(), strdup(counter), regex)); - ++count; + bool addCounter = true; + const char *enable = mxmlElementGetAttr(node, "enable"); + if (enable != NULL) { + char buf[1<<10]; + snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%s/enable", enable); + if (access(buf, W_OK) != 0) { + logg->logMessage("Disabling counter %s, %s not found", counter, buf); + addCounter = false; + } + } + if (addCounter) { + setCounters(new FtraceCounter(getCounters(), strdup(counter), regex, enable)); + ++count; + } } mValues = new int64_t[2*count]; } +void FtraceDriver::prepare() { + for (FtraceCounter *counter = static_cast(getCounters()); counter != NULL; counter = static_cast(counter->getNext())) { + if (!counter->isEnabled()) { + continue; + } + counter->prepare(); + } +} + int FtraceDriver::read(const char *line, int64_t **buf) { int count = 0; @@ -116,3 +184,12 @@ int FtraceDriver::read(const char *line, int64_t **buf) { *buf = mValues; return count; } + +void FtraceDriver::stop() { + for (FtraceCounter *counter = static_cast(getCounters()); counter != NULL; counter = static_cast(counter->getNext())) { + if (!counter->isEnabled()) { + continue; + } + counter->stop(); + } +} diff --git a/tools/gator/daemon/FtraceDriver.h b/tools/gator/daemon/FtraceDriver.h index 5f958bec672c..b79dc9149d6a 100644 --- a/tools/gator/daemon/FtraceDriver.h +++ b/tools/gator/daemon/FtraceDriver.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2014. All rights reserved. + * Copyright (C) ARM Limited 2014-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -18,7 +18,9 @@ public: void readEvents(mxml_node_t *const xml); + void prepare(); int read(const char *line, int64_t **buf); + void stop(); private: int64_t *mValues; diff --git a/tools/gator/daemon/FtraceSource.cpp b/tools/gator/daemon/FtraceSource.cpp index 521633357417..14a48b3b870c 100644 --- a/tools/gator/daemon/FtraceSource.cpp +++ b/tools/gator/daemon/FtraceSource.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -14,10 +14,13 @@ #include #include +#include "Child.h" #include "DriverSource.h" #include "Logging.h" #include "SessionData.h" +extern Child *child; + static void handler(int signum) { (void)signum; @@ -35,18 +38,20 @@ bool FtraceSource::prepare() { act.sa_handler = handler; act.sa_flags = (int)SA_RESETHAND; if (sigaction(SIGUSR1, &act, NULL) != 0) { - logg->logError(__FILE__, __LINE__, "sigaction failed: %s\n", strerror(errno)); + logg->logError("sigaction failed: %s\n", strerror(errno)); handleException(); } } + gSessionData->ftraceDriver.prepare(); + if (DriverSource::readIntDriver("/sys/kernel/debug/tracing/tracing_on", &mTracingOn)) { - logg->logError(__FILE__, __LINE__, "Unable to read if ftrace is enabled"); + logg->logError("Unable to read if ftrace is enabled"); handleException(); } if (DriverSource::writeDriver("/sys/kernel/debug/tracing/tracing_on", "0") != 0) { - logg->logError(__FILE__, __LINE__, "Unable to turn ftrace off before truncating the buffer"); + logg->logError("Unable to turn ftrace off before truncating the buffer"); handleException(); } @@ -54,20 +59,20 @@ bool FtraceSource::prepare() { int fd; fd = open("/sys/kernel/debug/tracing/trace", O_WRONLY | O_TRUNC | O_CLOEXEC, 0666); if (fd < 0) { - logg->logError(__FILE__, __LINE__, "Unable truncate ftrace buffer: %s", strerror(errno)); + logg->logError("Unable truncate ftrace buffer: %s", strerror(errno)); handleException(); } close(fd); } if (DriverSource::writeDriver("/sys/kernel/debug/tracing/trace_clock", "perf") != 0) { - logg->logError(__FILE__, __LINE__, "Unable to switch ftrace to the perf clock, please ensure you are running Linux 3.10 or later"); + logg->logError("Unable to switch ftrace to the perf clock, please ensure you are running Linux 3.10 or later"); handleException(); } mFtraceFh = fopen_cloexec("/sys/kernel/debug/tracing/trace_pipe", "rb"); if (mFtraceFh == NULL) { - logg->logError(__FILE__, __LINE__, "Unable to open trace_pipe"); + logg->logError("Unable to open trace_pipe"); handleException(); } @@ -79,10 +84,25 @@ void FtraceSource::run() { mTid = syscall(__NR_gettid); if (DriverSource::writeDriver("/sys/kernel/debug/tracing/tracing_on", "1") != 0) { - logg->logError(__FILE__, __LINE__, "Unable to turn ftrace on"); + logg->logError("Unable to turn ftrace on"); handleException(); } + // Wait until monotonicStarted is set before sending data + int64_t monotonicStarted = 0; + while (monotonicStarted <= 0 && gSessionData->mSessionIsActive) { + usleep(10); + + if (gSessionData->perf.isSetup()) { + monotonicStarted = gSessionData->mMonotonicStarted; + } else { + if (DriverSource::readInt64Driver("/dev/gator/started", &monotonicStarted) == -1) { + logg->logError("Error reading gator driver start time"); + handleException(); + } + } + } + while (gSessionData->mSessionIsActive) { char buf[1<<12]; @@ -91,22 +111,26 @@ void FtraceSource::run() { // Interrupted by interrupt - likely user request to terminate break; } - logg->logError(__FILE__, __LINE__, "Unable read trace data: %s", strerror(errno)); + logg->logError("Unable read trace data: %s", strerror(errno)); handleException(); } - const uint64_t currTime = getTime(); + const uint64_t currTime = getTime() - gSessionData->mMonotonicStarted; char *const colon = strstr(buf, ": "); if (colon == NULL) { - logg->logError(__FILE__, __LINE__, "Unable find colon: %s", buf); + if (strstr(buf, " [LOST ") != NULL) { + logg->logError("Ftrace events lost, aborting the capture. It is recommended to discard this report and collect a new capture. If this error occurs often, please reduce the number of ftrace counters selected or the amount of ftrace events generated."); + } else { + logg->logError("Unable to find colon: %s", buf); + } handleException(); } *colon = '\0'; char *const space = strrchr(buf, ' '); if (space == NULL) { - logg->logError(__FILE__, __LINE__, "Unable find space: %s", buf); + logg->logError("Unable to find space: %s", buf); handleException(); } *colon = ':'; @@ -117,7 +141,7 @@ void FtraceSource::run() { errno = 0; const long long time = strtod(space, NULL) * 1000000000; if (errno != 0) { - logg->logError(__FILE__, __LINE__, "Unable to parse time: %s", strerror(errno)); + logg->logError("Unable to parse time: %s", strerror(errno)); handleException(); } mBuffer.event64(-1, time); @@ -127,6 +151,11 @@ void FtraceSource::run() { } mBuffer.check(currTime); + + if (gSessionData->mOneShot && gSessionData->mSessionIsActive && (mBuffer.bytesAvailable() <= 0)) { + logg->logMessage("One shot (ftrace)"); + child->endSession(); + } } } @@ -136,6 +165,7 @@ void FtraceSource::run() { DriverSource::writeDriver("/sys/kernel/debug/tracing/tracing_on", mTracingOn); fclose(mFtraceFh); DriverSource::writeDriver("/sys/kernel/debug/tracing/trace_clock", "local"); + gSessionData->ftraceDriver.stop(); } void FtraceSource::interrupt() { diff --git a/tools/gator/daemon/FtraceSource.h b/tools/gator/daemon/FtraceSource.h index 2391b881494e..bc068d266654 100644 --- a/tools/gator/daemon/FtraceSource.h +++ b/tools/gator/daemon/FtraceSource.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/HwmonDriver.cpp b/tools/gator/daemon/HwmonDriver.cpp index 9d161ae5ac56..d8353b006e63 100644 --- a/tools/gator/daemon/HwmonDriver.cpp +++ b/tools/gator/daemon/HwmonDriver.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -23,7 +23,7 @@ static sensors_subfeature_type getInput(const sensors_feature_type type) { case SENSORS_FEATURE_CURR: return SENSORS_SUBFEATURE_CURR_INPUT; case SENSORS_FEATURE_HUMIDITY: return SENSORS_SUBFEATURE_HUMIDITY_INPUT; default: - logg->logError(__FILE__, __LINE__, "Unsupported hwmon feature %i", type); + logg->logError("Unsupported hwmon feature %i", type); handleException(); } }; @@ -33,112 +33,112 @@ public: HwmonCounter(DriverCounter *next, char *const name, const sensors_chip_name *chip, const sensors_feature *feature); ~HwmonCounter(); - const char *getLabel() const { return label; } - const char *getTitle() const { return title; } - bool isDuplicate() const { return duplicate; } - const char *getDisplay() const { return display; } - const char *getCounterClass() const { return counter_class; } - const char *getUnit() const { return unit; } - int getModifier() const { return modifier; } + const char *getLabel() const { return mLabel; } + const char *getTitle() const { return mTitle; } + bool isDuplicate() const { return mDuplicate; } + const char *getDisplay() const { return mDisplay; } + const char *getCounterClass() const { return mCounterClass; } + const char *getUnit() const { return mUnit; } + double getMultiplier() const { return mMultiplier; } int64_t read(); private: void init(const sensors_chip_name *chip, const sensors_feature *feature); - const sensors_chip_name *chip; - const sensors_feature *feature; - char *label; - const char *title; - const char *display; - const char *counter_class; - const char *unit; - double previous_value; - int modifier; - int monotonic: 1, - duplicate : 1; + const sensors_chip_name *mChip; + const sensors_feature *mFeature; + char *mLabel; + const char *mTitle; + const char *mDisplay; + const char *mCounterClass; + const char *mUnit; + double mPreviousValue; + double mMultiplier; + int mMonotonic: 1, + mDuplicate : 1; // Intentionally unimplemented HwmonCounter(const HwmonCounter &); HwmonCounter &operator=(const HwmonCounter &); }; -HwmonCounter::HwmonCounter(DriverCounter *next, char *const name, const sensors_chip_name *chip, const sensors_feature *feature) : DriverCounter(next, name), chip(chip), feature(feature), duplicate(false) { - label = sensors_get_label(chip, feature); +HwmonCounter::HwmonCounter(DriverCounter *next, char *const name, const sensors_chip_name *const chip, const sensors_feature *feature) : DriverCounter(next, name), mChip(chip), mFeature(feature), mDuplicate(false) { + mLabel = sensors_get_label(mChip, mFeature); - switch (feature->type) { + switch (mFeature->type) { case SENSORS_FEATURE_IN: - title = "Voltage"; - display = "maximum"; - counter_class = "absolute"; - unit = "V"; - modifier = 1000; - monotonic = false; + mTitle = "Voltage"; + mDisplay = "maximum"; + mCounterClass = "absolute"; + mUnit = "V"; + mMultiplier = 0.001; + mMonotonic = false; break; case SENSORS_FEATURE_FAN: - title = "Fan"; - display = "average"; - counter_class = "absolute"; - unit = "RPM"; - modifier = 1; - monotonic = false; + mTitle = "Fan"; + mDisplay = "average"; + mCounterClass = "absolute"; + mUnit = "RPM"; + mMultiplier = 1.0; + mMonotonic = false; break; case SENSORS_FEATURE_TEMP: - title = "Temperature"; - display = "maximum"; - counter_class = "absolute"; - unit = "°C"; - modifier = 1000; - monotonic = false; + mTitle = "Temperature"; + mDisplay = "maximum"; + mCounterClass = "absolute"; + mUnit = "°C"; + mMultiplier = 0.001; + mMonotonic = false; break; case SENSORS_FEATURE_POWER: - title = "Power"; - display = "maximum"; - counter_class = "absolute"; - unit = "W"; - modifier = 1000000; - monotonic = false; + mTitle = "Power"; + mDisplay = "maximum"; + mCounterClass = "absolute"; + mUnit = "W"; + mMultiplier = 0.000001; + mMonotonic = false; break; case SENSORS_FEATURE_ENERGY: - title = "Energy"; - display = "accumulate"; - counter_class = "delta"; - unit = "J"; - modifier = 1000000; - monotonic = true; + mTitle = "Energy"; + mDisplay = "accumulate"; + mCounterClass = "delta"; + mUnit = "J"; + mMultiplier = 0.000001; + mMonotonic = true; break; case SENSORS_FEATURE_CURR: - title = "Current"; - display = "maximum"; - counter_class = "absolute"; - unit = "A"; - modifier = 1000; - monotonic = false; + mTitle = "Current"; + mDisplay = "maximum"; + mCounterClass = "absolute"; + mUnit = "A"; + mMultiplier = 0.001; + mMonotonic = false; break; case SENSORS_FEATURE_HUMIDITY: - title = "Humidity"; - display = "average"; - counter_class = "absolute"; - unit = "%"; - modifier = 1000; - monotonic = false; + mTitle = "Humidity"; + mDisplay = "average"; + mCounterClass = "absolute"; + mUnit = "%"; + mMultiplier = 0.001; + mMonotonic = false; break; default: - logg->logError(__FILE__, __LINE__, "Unsupported hwmon feature %i", feature->type); + logg->logError("Unsupported hwmon feature %i", mFeature->type); handleException(); } for (HwmonCounter * counter = static_cast(next); counter != NULL; counter = static_cast(counter->getNext())) { - if (strcmp(label, counter->getLabel()) == 0 && strcmp(title, counter->getTitle()) == 0) { - duplicate = true; - counter->duplicate = true; + if (strcmp(mLabel, counter->getLabel()) == 0 && strcmp(mTitle, counter->getTitle()) == 0) { + mDuplicate = true; + counter->mDuplicate = true; break; } } } HwmonCounter::~HwmonCounter() { - free((void *)label); + free((void *)mLabel); } int64_t HwmonCounter::read() { @@ -147,19 +147,19 @@ int64_t HwmonCounter::read() { const sensors_subfeature *subfeature; // Keep in sync with the read check in HwmonDriver::readEvents - subfeature = sensors_get_subfeature(chip, feature, getInput(feature->type)); + subfeature = sensors_get_subfeature(mChip, mFeature, getInput(mFeature->type)); if (!subfeature) { - logg->logError(__FILE__, __LINE__, "No input value for hwmon sensor %s", label); + logg->logError("No input value for hwmon sensor %s", mLabel); handleException(); } - if (sensors_get_value(chip, subfeature->number, &value) != 0) { - logg->logError(__FILE__, __LINE__, "Can't get input value for hwmon sensor %s", label); + if (sensors_get_value(mChip, subfeature->number, &value) != 0) { + logg->logError("Can't get input value for hwmon sensor %s", mLabel); handleException(); } - result = (monotonic ? value - previous_value : value); - previous_value = value; + result = (mMonotonic ? value - mPreviousValue : value); + mPreviousValue = value; return result; } @@ -209,7 +209,7 @@ void HwmonDriver::readEvents(mxml_node_t *const) { void HwmonDriver::writeEvents(mxml_node_t *root) const { root = mxmlNewElement(root, "category"); - mxmlElementSetAttr(root, "name", "hwmon"); + mxmlElementSetAttr(root, "name", "Hardware Monitor"); char buf[1024]; for (HwmonCounter *counter = static_cast(getCounters()); counter != NULL; counter = static_cast(counter->getNext())) { @@ -224,8 +224,8 @@ void HwmonDriver::writeEvents(mxml_node_t *root) const { mxmlElementSetAttr(node, "display", counter->getDisplay()); mxmlElementSetAttr(node, "class", counter->getCounterClass()); mxmlElementSetAttr(node, "units", counter->getUnit()); - if (counter->getModifier() != 1) { - mxmlElementSetAttrf(node, "modifier", "%d", counter->getModifier()); + if (counter->getMultiplier() != 1.0) { + mxmlElementSetAttrf(node, "multiplier", "%lf", counter->getMultiplier()); } if (strcmp(counter->getDisplay(), "average") == 0 || strcmp(counter->getDisplay(), "maximum") == 0) { mxmlElementSetAttr(node, "average_selection", "yes"); diff --git a/tools/gator/daemon/HwmonDriver.h b/tools/gator/daemon/HwmonDriver.h index f28d825e3b7b..f15d557051dc 100644 --- a/tools/gator/daemon/HwmonDriver.h +++ b/tools/gator/daemon/HwmonDriver.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/KMod.cpp b/tools/gator/daemon/KMod.cpp index fe9dc6a7e4f7..e33b499d831b 100644 --- a/tools/gator/daemon/KMod.cpp +++ b/tools/gator/daemon/KMod.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -83,13 +83,13 @@ void KMod::setupCounter(Counter &counter) { if (access(text, F_OK) == 0) { int count = counter.getCount(); if (DriverSource::writeReadDriver(text, &count) && counter.getCount() > 0) { - logg->logError(__FILE__, __LINE__, "Cannot enable EBS for %s:%i with a count of %d\n", counter.getType(), counter.getEvent(), counter.getCount()); + logg->logError("Cannot enable EBS for %s:%i with a count of %d\n", counter.getType(), counter.getEvent(), counter.getCount()); handleException(); } counter.setCount(count); } else if (counter.getCount() > 0) { ConfigurationXML::remove(); - 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"); + logg->logError("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"); handleException(); } } diff --git a/tools/gator/daemon/KMod.h b/tools/gator/daemon/KMod.h index 900a60e87d24..7f06b4b34b5d 100644 --- a/tools/gator/daemon/KMod.h +++ b/tools/gator/daemon/KMod.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/LocalCapture.cpp b/tools/gator/daemon/LocalCapture.cpp index d2a4b799d7ac..56899871c03a 100644 --- a/tools/gator/daemon/LocalCapture.cpp +++ b/tools/gator/daemon/LocalCapture.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -27,7 +27,7 @@ LocalCapture::~LocalCapture() {} void LocalCapture::createAPCDirectory(char* target_path) { gSessionData->mAPCDir = createUniqueDirectory(target_path, ".apc"); if ((removeDirAndAllContents(gSessionData->mAPCDir) != 0 || mkdir(gSessionData->mAPCDir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0)) { - logg->logError(__FILE__, __LINE__, "Unable to create directory %s", gSessionData->mAPCDir); + logg->logError("Unable to create directory %s", gSessionData->mAPCDir); handleException(); } } @@ -40,7 +40,7 @@ void LocalCapture::write(char* string) { // Write the file if (util->writeToDisk(file, string) < 0) { - logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify the path.", file); + logg->logError("Error writing %s\nPlease verify the path.", file); handleException(); } @@ -55,7 +55,7 @@ char* LocalCapture::createUniqueDirectory(const char* initialPath, const char* e // Ensure the path is an absolute path, i.e. starts with a slash if (initialPath == 0 || strlen(initialPath) == 0) { - logg->logError(__FILE__, __LINE__, "Missing -o command line option required for a local capture."); + logg->logError("Missing -o command line option required for a local capture."); handleException(); } else if (initialPath[0] != '/') { if (getcwd(path, PATH_MAX) == 0) { diff --git a/tools/gator/daemon/LocalCapture.h b/tools/gator/daemon/LocalCapture.h index 25d281f8328b..807f49d16845 100644 --- a/tools/gator/daemon/LocalCapture.h +++ b/tools/gator/daemon/LocalCapture.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/Logging.cpp b/tools/gator/daemon/Logging.cpp index 41ffa1a45151..8846622d950f 100644 --- a/tools/gator/daemon/Logging.cpp +++ b/tools/gator/daemon/Logging.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -39,12 +39,12 @@ Logging::Logging(bool debug) { Logging::~Logging() { } -void Logging::logError(const char* file, int line, const char* fmt, ...) { +void Logging::_logError(const char *function, const char *file, int line, const char *fmt, ...) { va_list args; MUTEX_LOCK(); if (mDebug) { - snprintf(mErrBuf, sizeof(mErrBuf), "ERROR[%s:%d]: ", file, line); + snprintf(mErrBuf, sizeof(mErrBuf), "ERROR: %s(%s:%i): ", function, file, line); } else { mErrBuf[0] = 0; } @@ -59,12 +59,12 @@ void Logging::logError(const char* file, int line, const char* fmt, ...) { MUTEX_UNLOCK(); } -void Logging::logMessage(const char* fmt, ...) { +void Logging::_logMessage(const char *function, const char *file, int line, const char *fmt, ...) { if (mDebug) { va_list args; MUTEX_LOCK(); - strcpy(mLogBuf, "INFO: "); + snprintf(mLogBuf, sizeof(mLogBuf), "INFO: %s(%s:%i): ", function, file, line); va_start(args, fmt); vsnprintf(mLogBuf + strlen(mLogBuf), sizeof(mLogBuf) - 2 - strlen(mLogBuf), fmt, args); // subtract 2 for \n and \0 diff --git a/tools/gator/daemon/Logging.h b/tools/gator/daemon/Logging.h index 09e93ff13f7a..a7b45239f5d8 100644 --- a/tools/gator/daemon/Logging.h +++ b/tools/gator/daemon/Logging.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -17,10 +17,14 @@ class Logging { public: Logging(bool debug); ~Logging(); - void logError(const char* file, int line, const char* fmt, ...); - void logMessage(const char* fmt, ...); - char* getLastError() {return mErrBuf;} - char* getLastMessage() {return mLogBuf;} +#define logError(...) _logError(__func__, __FILE__, __LINE__, __VA_ARGS__) + __attribute__ ((format (printf, 5, 6))) + void _logError(const char *function, const char *file, int line, const char *fmt, ...); +#define logMessage(...) _logMessage(__func__, __FILE__, __LINE__, __VA_ARGS__) + __attribute__ ((format (printf, 5, 6))) + void _logMessage(const char *function, const char *file, int line, const char *fmt, ...); + char *getLastError() {return mErrBuf;} + char *getLastMessage() {return mLogBuf;} private: char mErrBuf[4096]; // Arbitrarily large buffer to hold a string @@ -29,7 +33,7 @@ private: pthread_mutex_t mLoggingMutex; }; -extern Logging* logg; +extern Logging *logg; extern void handleException() __attribute__ ((noreturn)); diff --git a/tools/gator/daemon/MaliVideoDriver.cpp b/tools/gator/daemon/MaliVideoDriver.cpp index 5eef2643ab15..2db332d3e2e4 100644 --- a/tools/gator/daemon/MaliVideoDriver.cpp +++ b/tools/gator/daemon/MaliVideoDriver.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2014. All rights reserved. + * Copyright (C) ARM Limited 2014-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -109,7 +109,7 @@ static bool writeAll(const int mveUds, const char *const buf, const int pos) { while (written < pos) { size_t bytes = ::write(mveUds, buf + written, pos - written); if (bytes <= 0) { - logg->logMessage("%s(%s:%i): write failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("write failed"); return false; } written += bytes; diff --git a/tools/gator/daemon/MaliVideoDriver.h b/tools/gator/daemon/MaliVideoDriver.h index 204a57a447ac..35b0558e390b 100644 --- a/tools/gator/daemon/MaliVideoDriver.h +++ b/tools/gator/daemon/MaliVideoDriver.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2014. All rights reserved. + * Copyright (C) ARM Limited 2014-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/MemInfoDriver.cpp b/tools/gator/daemon/MemInfoDriver.cpp index cce15c16fcdc..6818b978dc5b 100644 --- a/tools/gator/daemon/MemInfoDriver.cpp +++ b/tools/gator/daemon/MemInfoDriver.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -59,7 +59,7 @@ void MemInfoDriver::read(Buffer *const buffer) { } if (!mBuf.read("/proc/meminfo")) { - logg->logError(__FILE__, __LINE__, "Failed to read /proc/meminfo"); + logg->logError("Failed to read /proc/meminfo"); handleException(); } diff --git a/tools/gator/daemon/MemInfoDriver.h b/tools/gator/daemon/MemInfoDriver.h index eb1b0417f309..ffeaf3009e93 100644 --- a/tools/gator/daemon/MemInfoDriver.h +++ b/tools/gator/daemon/MemInfoDriver.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/Monitor.cpp b/tools/gator/daemon/Monitor.cpp index 74f22ee29fec..04288872f515 100644 --- a/tools/gator/daemon/Monitor.cpp +++ b/tools/gator/daemon/Monitor.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -38,17 +38,17 @@ bool Monitor::init() { mFd = epoll_create(16); #endif if (mFd < 0) { - logg->logMessage("%s(%s:%i): epoll_create1 failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("epoll_create1 failed"); return false; } #ifndef EPOLL_CLOEXEC - int fdf = fcntl(mFd, F_GETFD); - if ((fdf == -1) || (fcntl(mFd, F_SETFD, fdf | FD_CLOEXEC) != 0)) { - logg->logMessage("%s(%s:%i): fcntl failed", __FUNCTION__, __FILE__, __LINE__); - ::close(mFd); - return -1; - } + int fdf = fcntl(mFd, F_GETFD); + if ((fdf == -1) || (fcntl(mFd, F_SETFD, fdf | FD_CLOEXEC) != 0)) { + logg->logMessage("fcntl failed"); + ::close(mFd); + return -1; + } #endif return true; @@ -60,7 +60,7 @@ bool Monitor::add(const int fd) { event.data.fd = fd; event.events = EPOLLIN; if (epoll_ctl(mFd, EPOLL_CTL_ADD, fd, &event) != 0) { - logg->logMessage("%s(%s:%i): epoll_ctl failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("epoll_ctl failed"); return false; } @@ -74,7 +74,7 @@ int Monitor::wait(struct epoll_event *const events, int maxevents, int timeout) if (errno == EINTR) { result = 0; } else { - logg->logMessage("%s(%s:%i): epoll_wait failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("epoll_wait failed"); } } diff --git a/tools/gator/daemon/Monitor.h b/tools/gator/daemon/Monitor.h index 7194e0e4ca50..55368fca3e0a 100644 --- a/tools/gator/daemon/Monitor.h +++ b/tools/gator/daemon/Monitor.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/NetDriver.cpp b/tools/gator/daemon/NetDriver.cpp index e75c0695779a..56b25e0cfa63 100644 --- a/tools/gator/daemon/NetDriver.cpp +++ b/tools/gator/daemon/NetDriver.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -108,7 +108,7 @@ bool NetDriver::doRead() { void NetDriver::start() { if (!doRead()) { - logg->logError(__FILE__, __LINE__, "Unable to read network stats"); + logg->logError("Unable to read network stats"); handleException(); } // Initialize previous values @@ -122,7 +122,7 @@ void NetDriver::start() { void NetDriver::read(Buffer *const buffer) { if (!doRead()) { - logg->logError(__FILE__, __LINE__, "Unable to read network stats"); + logg->logError("Unable to read network stats"); handleException(); } super::read(buffer); diff --git a/tools/gator/daemon/NetDriver.h b/tools/gator/daemon/NetDriver.h index 50ff850bfc6d..5f722800f75f 100644 --- a/tools/gator/daemon/NetDriver.h +++ b/tools/gator/daemon/NetDriver.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/OlySocket.cpp b/tools/gator/daemon/OlySocket.cpp index aa0ce4929916..078d20209226 100644 --- a/tools/gator/daemon/OlySocket.cpp +++ b/tools/gator/daemon/OlySocket.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -19,6 +19,7 @@ #include #include #include +#include #endif #include "Logging.h" @@ -78,7 +79,7 @@ OlyServerSocket::OlyServerSocket(int port) { #ifdef WIN32 WSADATA wsaData; if (WSAStartup(0x0202, &wsaData) != 0) { - logg->logError(__FILE__, __LINE__, "Windows socket initialization failed"); + logg->logError("Windows socket initialization failed"); handleException(); } #endif @@ -97,11 +98,11 @@ OlySocket::OlySocket(int socketID) : mSocketID(socketID) { __a > __b ? __b : __a; \ }) -OlyServerSocket::OlyServerSocket(const char* path, const size_t pathSize) { +OlyServerSocket::OlyServerSocket(const char* path, const size_t pathSize, const bool calculateAddrlen) { // Create socket mFDServer = socket_cloexec(PF_UNIX, SOCK_STREAM, 0); if (mFDServer < 0) { - logg->logError(__FILE__, __LINE__, "Error creating server socket"); + logg->logError("Error creating server socket"); handleException(); } @@ -113,19 +114,19 @@ OlyServerSocket::OlyServerSocket(const char* path, const size_t pathSize) { sockaddr.sun_path[sizeof(sockaddr.sun_path) - 1] = '\0'; // Bind the socket to an address - if (bind(mFDServer, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) { - logg->logError(__FILE__, __LINE__, "Binding of server socket failed."); + if (bind(mFDServer, (const struct sockaddr*)&sockaddr, calculateAddrlen ? offsetof(struct sockaddr_un, sun_path) + pathSize - 1 : sizeof(sockaddr)) < 0) { + logg->logError("Binding of server socket failed."); handleException(); } // Listen for connections on this socket if (listen(mFDServer, 1) < 0) { - logg->logError(__FILE__, __LINE__, "Listening of server socket failed"); + logg->logError("Listening of server socket failed"); handleException(); } } -int OlySocket::connect(const char* path, const size_t pathSize) { +int OlySocket::connect(const char* path, const size_t pathSize, const bool calculateAddrlen) { int fd = socket_cloexec(PF_UNIX, SOCK_STREAM, 0); if (fd < 0) { return -1; @@ -138,7 +139,7 @@ int OlySocket::connect(const char* path, const size_t pathSize) { memcpy(sockaddr.sun_path, path, MIN(pathSize, sizeof(sockaddr.sun_path))); sockaddr.sun_path[sizeof(sockaddr.sun_path) - 1] = '\0'; - if (::connect(fd, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) { + if (::connect(fd, (const struct sockaddr*)&sockaddr, calculateAddrlen ? offsetof(struct sockaddr_un, sun_path) + pathSize - 1 : sizeof(sockaddr)) < 0) { close(fd); return -1; } @@ -174,11 +175,11 @@ void OlySocket::closeSocket() { } void OlyServerSocket::closeServerSocket() { - if (CLOSE_SOCKET(mFDServer) != 0) { - logg->logError(__FILE__, __LINE__, "Failed to close server socket."); + if (mFDServer > 0 && CLOSE_SOCKET(mFDServer) != 0) { + logg->logError("Failed to close server socket."); handleException(); } - mFDServer = 0; + mFDServer = -1; } void OlyServerSocket::createServerSocket(int port) { @@ -190,7 +191,7 @@ void OlyServerSocket::createServerSocket(int port) { family = AF_INET; mFDServer = socket_cloexec(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (mFDServer < 0) { - logg->logError(__FILE__, __LINE__, "Error creating server socket"); + logg->logError("Error creating server socket"); handleException(); } } @@ -198,10 +199,16 @@ void OlyServerSocket::createServerSocket(int port) { // Enable address reuse, another solution would be to create the server socket once and only close it when the object exits int on = 1; if (setsockopt(mFDServer, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)) != 0) { - logg->logError(__FILE__, __LINE__, "Setting server socket options failed"); + logg->logError("Setting server socket reuse option failed"); handleException(); } + // Listen on both IPv4 and IPv6 + on = 0; + if (setsockopt(mFDServer, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&on, sizeof(on)) != 0) { + logg->logMessage("setsockopt IPV6_V6ONLY failed"); + } + // Create sockaddr_in structure, ensuring non-populated fields are zero struct sockaddr_in6 sockaddr; memset((void*)&sockaddr, 0, sizeof(sockaddr)); @@ -211,13 +218,13 @@ void OlyServerSocket::createServerSocket(int port) { // Bind the socket to an address if (bind(mFDServer, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) { - logg->logError(__FILE__, __LINE__, "Binding of server socket failed.\nIs an instance already running?"); + logg->logError("Binding of server socket on port %i failed.\nIs an instance already running or is another application using that port?", port); handleException(); } // Listen for connections on this socket if (listen(mFDServer, 1) < 0) { - logg->logError(__FILE__, __LINE__, "Listening of server socket failed"); + logg->logError("Listening of server socket failed"); handleException(); } } @@ -227,14 +234,14 @@ void OlyServerSocket::createServerSocket(int port) { int OlyServerSocket::acceptConnection() { int socketID; if (mFDServer <= 0) { - logg->logError(__FILE__, __LINE__, "Attempting multiple connections on a single connection server socket or attempting to accept on a client socket"); + logg->logError("Attempting multiple connections on a single connection server socket or attempting to accept on a client socket"); handleException(); } // Accept a connection, note that this call blocks until a client connects socketID = accept_cloexec(mFDServer, NULL, NULL); if (socketID < 0) { - logg->logError(__FILE__, __LINE__, "Socket acceptance failed"); + logg->logError("Socket acceptance failed"); handleException(); } return socketID; @@ -248,7 +255,7 @@ void OlySocket::send(const char* buffer, int size) { while (size > 0) { int n = ::send(mSocketID, buffer, size, 0); if (n < 0) { - logg->logError(__FILE__, __LINE__, "Socket send error"); + logg->logError("Socket send error"); handleException(); } size -= n; @@ -264,7 +271,7 @@ int OlySocket::receive(char* buffer, int size) { int bytes = recv(mSocketID, buffer, size, 0); if (bytes < 0) { - logg->logError(__FILE__, __LINE__, "Socket receive error"); + logg->logError("Socket receive error"); handleException(); } else if (bytes == 0) { logg->logMessage("Socket disconnected"); @@ -279,7 +286,7 @@ int OlySocket::receiveNBytes(char* buffer, int size) { while (size > 0 && buffer != NULL) { bytes = recv(mSocketID, buffer, size, 0); if (bytes < 0) { - logg->logError(__FILE__, __LINE__, "Socket receive error"); + logg->logError("Socket receive error"); handleException(); } else if (bytes == 0) { logg->logMessage("Socket disconnected"); @@ -304,7 +311,7 @@ int OlySocket::receiveString(char* buffer, int size) { // Receive a single character int bytes = recv(mSocketID, &buffer[bytes_received], 1, 0); if (bytes < 0) { - logg->logError(__FILE__, __LINE__, "Socket receive error"); + logg->logError("Socket receive error"); handleException(); } else if (bytes == 0) { logg->logMessage("Socket disconnected"); diff --git a/tools/gator/daemon/OlySocket.h b/tools/gator/daemon/OlySocket.h index 6b53b01fc3ee..757a2522f926 100644 --- a/tools/gator/daemon/OlySocket.h +++ b/tools/gator/daemon/OlySocket.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -12,7 +12,7 @@ #include #ifdef WIN32 -typedef socklen_t int; +typedef int socklen_t; #else #include #endif @@ -20,7 +20,7 @@ typedef socklen_t int; class OlySocket { public: #ifndef WIN32 - static int connect(const char* path, const size_t pathSize); + static int connect(const char* path, const size_t pathSize, const bool calculateAddrlen = false); #endif OlySocket(int socketID); @@ -43,7 +43,7 @@ class OlyServerSocket { public: OlyServerSocket(int port); #ifndef WIN32 - OlyServerSocket(const char* path, const size_t pathSize); + OlyServerSocket(const char* path, const size_t pathSize, const bool calculateAddrlen = false); #endif ~OlyServerSocket(); diff --git a/tools/gator/daemon/OlyUtility.cpp b/tools/gator/daemon/OlyUtility.cpp index 45340a27d9fa..6f40168c1ee0 100644 --- a/tools/gator/daemon/OlyUtility.cpp +++ b/tools/gator/daemon/OlyUtility.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/OlyUtility.h b/tools/gator/daemon/OlyUtility.h index 1d26beb596fa..1525081a97a3 100644 --- a/tools/gator/daemon/OlyUtility.h +++ b/tools/gator/daemon/OlyUtility.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/PerfBuffer.cpp b/tools/gator/daemon/PerfBuffer.cpp index f127c996d43b..3b9da1dc6592 100644 --- a/tools/gator/daemon/PerfBuffer.cpp +++ b/tools/gator/daemon/PerfBuffer.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -35,14 +35,14 @@ PerfBuffer::~PerfBuffer() { bool PerfBuffer::useFd(const int cpu, const int fd) { if (mFds[cpu] < 0) { if (mBuf[cpu] != MAP_FAILED) { - logg->logMessage("%s(%s:%i): cpu %i already online or not correctly cleaned up", __FUNCTION__, __FILE__, __LINE__, cpu); + logg->logMessage("cpu %i already online or not correctly cleaned up", cpu); return false; } // The buffer isn't mapped yet mBuf[cpu] = mmap(NULL, gSessionData->mPageSize + BUF_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (mBuf[cpu] == MAP_FAILED) { - logg->logMessage("%s(%s:%i): mmap failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("mmap failed"); return false; } mFds[cpu] = fd; @@ -50,17 +50,17 @@ bool PerfBuffer::useFd(const int cpu, const int fd) { // Check the version struct perf_event_mmap_page *pemp = static_cast(mBuf[cpu]); if (pemp->compat_version != 0) { - logg->logMessage("%s(%s:%i): Incompatible perf_event_mmap_page compat_version", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("Incompatible perf_event_mmap_page compat_version"); return false; } } else { if (mBuf[cpu] == MAP_FAILED) { - logg->logMessage("%s(%s:%i): cpu already online or not correctly cleaned up", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("cpu already online or not correctly cleaned up"); return false; } if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, mFds[cpu]) < 0) { - logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("ioctl failed"); return false; } } @@ -79,8 +79,8 @@ bool PerfBuffer::isEmpty() { if (mBuf[cpu] != MAP_FAILED) { // Take a snapshot of the positions struct perf_event_mmap_page *pemp = static_cast(mBuf[cpu]); - const __u64 head = pemp->data_head; - const __u64 tail = pemp->data_tail; + const __u64 head = ACCESS_ONCE(pemp->data_head); + const __u64 tail = ACCESS_ONCE(pemp->data_tail); if (head != tail) { return false; @@ -91,42 +91,105 @@ bool PerfBuffer::isEmpty() { return true; } -static void compressAndSend(const int cpu, const __u64 head, __u64 tail, const uint8_t *const b, Sender *const sender) { - // Pick a big size but something smaller than the chunkSize in Sender::writeData which is 100k - char buf[1<<16]; - int writePos = 0; - const int typeLength = gSessionData->mLocalCapture ? 0 : 1; +bool PerfBuffer::isFull() { + for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) { + if (mBuf[cpu] != MAP_FAILED) { + // Take a snapshot of the positions + struct perf_event_mmap_page *pemp = static_cast(mBuf[cpu]); + const __u64 head = ACCESS_ONCE(pemp->data_head); - while (head > tail) { - writePos = 0; - if (!gSessionData->mLocalCapture) { - buf[writePos++] = RESPONSE_APC_DATA; + if (head + 2000 <= (unsigned int)BUF_SIZE) { + return true; + } } - // Reserve space for size - writePos += sizeof(uint32_t); - Buffer::packInt(buf, sizeof(buf), writePos, FRAME_PERF); - Buffer::packInt(buf, sizeof(buf), writePos, cpu); + } + + return false; +} + +class PerfFrame { +public: + PerfFrame(Sender *const sender) : mSender(sender), mWritePos(-1), mCpuSizePos(-1) {} + + void add(const int cpu, const __u64 head, __u64 tail, const uint8_t *const b) { + cpuHeader(cpu); while (head > tail) { const int count = reinterpret_cast(b + (tail & BUF_MASK))->size/sizeof(uint64_t); // Can this whole message be written as Streamline assumes events are not split between frames - if (sizeof(buf) <= writePos + count*Buffer::MAXSIZE_PACK64) { - break; + if (sizeof(mBuf) <= mWritePos + count*Buffer::MAXSIZE_PACK64) { + send(); + cpuHeader(cpu); } for (int i = 0; i < count; ++i) { // Must account for message size - Buffer::packInt64(buf, sizeof(buf), writePos, *reinterpret_cast(b + (tail & BUF_MASK))); + Buffer::packInt64(mBuf, sizeof(mBuf), mWritePos, *reinterpret_cast(b + (tail & BUF_MASK))); tail += sizeof(uint64_t); } } + } + + void send() { + if (mWritePos > 0) { + writeFrameSize(); + mSender->writeData(mBuf, mWritePos, RESPONSE_APC_DATA); + mWritePos = -1; + mCpuSizePos = -1; + } + } - // Write size - Buffer::writeLEInt(reinterpret_cast(buf + typeLength), writePos - typeLength - sizeof(uint32_t)); - sender->writeData(buf, writePos, RESPONSE_APC_DATA); +private: + void writeFrameSize() { + writeCpuSize(); + const int typeLength = gSessionData->mLocalCapture ? 0 : 1; + Buffer::writeLEInt(reinterpret_cast(mBuf + typeLength), mWritePos - typeLength - sizeof(uint32_t)); } -} + + void frameHeader() { + if (mWritePos < 0) { + mWritePos = 0; + mCpuSizePos = -1; + if (!gSessionData->mLocalCapture) { + mBuf[mWritePos++] = RESPONSE_APC_DATA; + } + // Reserve space for frame size + mWritePos += sizeof(uint32_t); + Buffer::packInt(mBuf, sizeof(mBuf), mWritePos, FRAME_PERF); + } + } + + void writeCpuSize() { + if (mCpuSizePos >= 0) { + Buffer::writeLEInt(reinterpret_cast(mBuf + mCpuSizePos), mWritePos - mCpuSizePos - sizeof(uint32_t)); + } + } + + void cpuHeader(const int cpu) { + if (sizeof(mBuf) <= mWritePos + Buffer::MAXSIZE_PACK32 + sizeof(uint32_t)) { + send(); + } + frameHeader(); + writeCpuSize(); + Buffer::packInt(mBuf, sizeof(mBuf), mWritePos, cpu); + mCpuSizePos = mWritePos; + // Reserve space for cpu size + mWritePos += sizeof(uint32_t); + } + + // Pick a big size but something smaller than the chunkSize in Sender::writeData which is 100k + char mBuf[1<<16]; + Sender *const mSender; + int mWritePos; + int mCpuSizePos; + + // Intentionally unimplemented + PerfFrame(const PerfFrame &); + PerfFrame& operator=(const PerfFrame &); +}; bool PerfBuffer::send(Sender *const sender) { + PerfFrame frame(sender); + for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) { if (mBuf[cpu] == MAP_FAILED) { continue; @@ -134,12 +197,12 @@ bool PerfBuffer::send(Sender *const sender) { // Take a snapshot of the positions struct perf_event_mmap_page *pemp = static_cast(mBuf[cpu]); - const __u64 head = pemp->data_head; - const __u64 tail = pemp->data_tail; + const __u64 head = ACCESS_ONCE(pemp->data_head); + const __u64 tail = ACCESS_ONCE(pemp->data_tail); if (head > tail) { const uint8_t *const b = static_cast(mBuf[cpu]) + gSessionData->mPageSize; - compressAndSend(cpu, head, tail, b, sender); + frame.add(cpu, head, tail, b); // Update tail with the data read pemp->data_tail = head; @@ -150,9 +213,11 @@ bool PerfBuffer::send(Sender *const sender) { mBuf[cpu] = MAP_FAILED; mDiscard[cpu] = false; mFds[cpu] = -1; - logg->logMessage("%s(%s:%i): Unmaped cpu %i", __FUNCTION__, __FILE__, __LINE__, cpu); + logg->logMessage("Unmaped cpu %i", cpu); } } + frame.send(); + return true; } diff --git a/tools/gator/daemon/PerfBuffer.h b/tools/gator/daemon/PerfBuffer.h index 25a10625a9e8..a2d0e9b44725 100644 --- a/tools/gator/daemon/PerfBuffer.h +++ b/tools/gator/daemon/PerfBuffer.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -24,6 +24,7 @@ public: bool useFd(const int cpu, const int fd); void discard(const int cpu); bool isEmpty(); + bool isFull(); bool send(Sender *const sender); private: diff --git a/tools/gator/daemon/PerfDriver.cpp b/tools/gator/daemon/PerfDriver.cpp index ee90284cee41..796ee7564c66 100644 --- a/tools/gator/daemon/PerfDriver.cpp +++ b/tools/gator/daemon/PerfDriver.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -40,24 +40,25 @@ struct gator_cpu { // From gator_main.c static const struct gator_cpu gator_cpus[] = { - { 0xb36, "ARM1136", "ARM_ARM11", 3 }, - { 0xb56, "ARM1156", "ARM_ARM11", 3 }, - { 0xb76, "ARM1176", "ARM_ARM11", 3 }, - { 0xb02, "ARM11MPCore", "ARM_ARM11MPCore", 3 }, - { 0xc05, "Cortex-A5", "ARMv7_Cortex_A5", 2 }, - { 0xc07, "Cortex-A7", "ARMv7_Cortex_A7", 4 }, - { 0xc08, "Cortex-A8", "ARMv7_Cortex_A8", 4 }, - { 0xc09, "Cortex-A9", "ARMv7_Cortex_A9", 6 }, - { 0xc0f, "Cortex-A15", "ARMv7_Cortex_A15", 6 }, - { 0xc0e, "Cortex-A17", "ARMv7_Cortex_A17", 6 }, - { 0x00f, "Scorpion", "Scorpion", 4 }, - { 0x02d, "ScorpionMP", "ScorpionMP", 4 }, - { 0x049, "KraitSIM", "Krait", 4 }, - { 0x04d, "Krait", "Krait", 4 }, - { 0x06f, "Krait S4 Pro", "Krait", 4 }, - { 0xd03, "Cortex-A53", "ARM_Cortex-A53", 6 }, - { 0xd07, "Cortex-A57", "ARM_Cortex-A57", 6 }, - { 0xd0f, "AArch64", "ARM_AArch64", 6 }, + { 0x41b36, "ARM1136", "ARM_ARM11", 3 }, + { 0x41b56, "ARM1156", "ARM_ARM11", 3 }, + { 0x41b76, "ARM1176", "ARM_ARM11", 3 }, + { 0x41b02, "ARM11MPCore", "ARM_ARM11MPCore", 3 }, + { 0x41c05, "Cortex-A5", "ARMv7_Cortex_A5", 2 }, + { 0x41c07, "Cortex-A7", "ARMv7_Cortex_A7", 4 }, + { 0x41c08, "Cortex-A8", "ARMv7_Cortex_A8", 4 }, + { 0x41c09, "Cortex-A9", "ARMv7_Cortex_A9", 6 }, + { 0x41c0f, "Cortex-A15", "ARMv7_Cortex_A15", 6 }, + { 0x41c0d, "Cortex-A17", "ARMv7_Cortex_A17", 6 }, + { 0x41c0e, "Cortex-A17", "ARMv7_Cortex_A17", 6 }, + { 0x5100f, "Scorpion", "Scorpion", 4 }, + { 0x5102d, "ScorpionMP", "ScorpionMP", 4 }, + { 0x51049, "KraitSIM", "Krait", 4 }, + { 0x5104d, "Krait", "Krait", 4 }, + { 0x5106f, "Krait S4 Pro", "Krait", 4 }, + { 0x41d03, "Cortex-A53", "ARM_Cortex-A53", 6 }, + { 0x41d07, "Cortex-A57", "ARM_Cortex-A57", 6 }, + { 0x41d08, "Cortex-A72", "ARM_Cortex-A72", 6 }, }; static const char OLD_PMU_PREFIX[] = "ARMv7 Cortex-"; @@ -69,17 +70,19 @@ struct uncore_counter { // gatorfs event name const char *const gatorName; const int count; + const bool hasCyclesCounter; }; static const struct uncore_counter uncore_counters[] = { - { "CCI_400", "CCI_400", 4 }, - { "CCI_400-r1", "CCI_400-r1", 4 }, - { "ccn", "ARM_CCN_5XX", 8 }, + { "CCI_400", "CCI_400", 4, true }, + { "CCI_400-r1", "CCI_400-r1", 4, true }, + { "CCI_500", "CCI_500", 8, false }, + { "ccn", "ARM_CCN_5XX", 8, true }, }; class PerfCounter : public DriverCounter { public: - PerfCounter(DriverCounter *next, const char *name, uint32_t type, uint64_t config, bool perCpu) : DriverCounter(next, name), mType(type), mCount(0), mConfig(config), mPerCpu(perCpu) {} + PerfCounter(DriverCounter *next, const char *name, uint32_t type, uint64_t config, uint64_t sampleType, uint64_t flags) : DriverCounter(next, name), mType(type), mConfig(config), mSampleType(sampleType), mFlags(flags), mCount(0) {} ~PerfCounter() { } @@ -89,13 +92,41 @@ public: void setCount(const int count) { mCount = count; } uint64_t getConfig() const { return mConfig; } void setConfig(const uint64_t config) { mConfig = config; } - bool isPerCpu() const { return mPerCpu; } + uint64_t getSampleType() const { return mSampleType; } + uint64_t getFlags() const { return mFlags; } + virtual void read(Buffer *const, const int) {} private: const uint32_t mType; - int mCount; uint64_t mConfig; - bool mPerCpu; + const uint64_t mSampleType; + const uint64_t mFlags; + int mCount; + + // Intentionally undefined + PerfCounter(const PerfCounter &); + PerfCounter &operator=(const PerfCounter &); +}; + +class CPUFreqDriver : public PerfCounter { +public: + CPUFreqDriver(DriverCounter *next, uint64_t id) : PerfCounter(next, "Linux_power_cpu_freq", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_RAW, PERF_GROUP_LEADER | PERF_GROUP_PER_CPU) {} + + void read(Buffer *const buffer, const int cpu) { + char buf[64]; + + snprintf(buf, sizeof(buf), "/sys/devices/system/cpu/cpu%i/cpufreq/cpuinfo_cur_freq", cpu); + int64_t freq; + if (DriverSource::readInt64Driver(buf, &freq) != 0) { + freq = 0; + } + buffer->perfCounter(cpu, getKey(), 1000*freq); + } + +private: + // Intentionally undefined + CPUFreqDriver(const CPUFreqDriver &); + CPUFreqDriver &operator=(const CPUFreqDriver &); }; PerfDriver::PerfDriver() : mIsSetup(false), mLegacySupport(false) { @@ -108,27 +139,32 @@ void PerfDriver::addCpuCounters(const char *const counterName, const int type, c int len = snprintf(NULL, 0, "%s_ccnt", counterName) + 1; char *name = new char[len]; snprintf(name, len, "%s_ccnt", counterName); - setCounters(new PerfCounter(getCounters(), name, type, -1, true)); + setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU)); for (int j = 0; j < numCounters; ++j) { len = snprintf(NULL, 0, "%s_cnt%d", counterName, j) + 1; name = new char[len]; snprintf(name, len, "%s_cnt%d", counterName, j); - setCounters(new PerfCounter(getCounters(), name, type, -1, true)); + setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU)); } } -void PerfDriver::addUncoreCounters(const char *const counterName, const int type, const int numCounters) { - int len = snprintf(NULL, 0, "%s_ccnt", counterName) + 1; - char *name = new char[len]; - snprintf(name, len, "%s_ccnt", counterName); - setCounters(new PerfCounter(getCounters(), name, type, -1, false)); +void PerfDriver::addUncoreCounters(const char *const counterName, const int type, const int numCounters, const bool hasCyclesCounter) { + int len; + char *name; + + if (hasCyclesCounter) { + len = snprintf(NULL, 0, "%s_ccnt", counterName) + 1; + name = new char[len]; + snprintf(name, len, "%s_ccnt", counterName); + setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, 0)); + } for (int j = 0; j < numCounters; ++j) { len = snprintf(NULL, 0, "%s_cnt%d", counterName, j) + 1; name = new char[len]; snprintf(name, len, "%s_cnt%d", counterName, j); - setCounters(new PerfCounter(getCounters(), name, type, -1, false)); + setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, 0)); } } @@ -136,18 +172,18 @@ bool PerfDriver::setup() { // Check the kernel version int release[3]; if (!getLinuxVersion(release)) { - logg->logMessage("%s(%s:%i): getLinuxVersion failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("getLinuxVersion failed"); return false; } if (KERNEL_VERSION(release[0], release[1], release[2]) < KERNEL_VERSION(3, 4, 0)) { - logg->logMessage("%s(%s:%i): Unsupported kernel version", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("Unsupported kernel version"); return false; } mLegacySupport = KERNEL_VERSION(release[0], release[1], release[2]) < KERNEL_VERSION(3, 12, 0); if (access(EVENTS_PATH, R_OK) != 0) { - logg->logMessage("%s(%s:%i): " EVENTS_PATH " does not exist, is CONFIG_TRACING and CONFIG_CONTEXT_SWITCH_TRACER enabled?", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage(EVENTS_PATH " does not exist, is CONFIG_TRACING and CONFIG_CONTEXT_SWITCH_TRACER enabled?"); return false; } @@ -155,7 +191,7 @@ bool PerfDriver::setup() { bool foundCpu = false; DIR *dir = opendir(PERF_DEVICES); if (dir == NULL) { - logg->logMessage("%s(%s:%i): opendif failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("opendir failed"); return false; } @@ -198,7 +234,7 @@ bool PerfDriver::setup() { } logg->logMessage("Adding uncore counters for %s", uncore_counters[i].gatorName); - addUncoreCounters(uncore_counters[i].gatorName, type, uncore_counters[i].count); + addUncoreCounters(uncore_counters[i].gatorName, type, uncore_counters[i].count, uncore_counters[i].hasCyclesCounter); } } closedir(dir); @@ -216,13 +252,11 @@ bool PerfDriver::setup() { } } - /* if (!foundCpu) { - // If all else fails, use the perf architected counters - // 9 because that's how many are in events-Perf-Hardware.xml - assume they can all be enabled at once - addCpuCounters("Perf_Hardware", PERF_TYPE_HARDWARE, 9); + // If all else fails, use the ARM architected counters + logg->logMessage("Using Other cpu"); + addCpuCounters("Other", PERF_TYPE_RAW, 6); } - */ // Add supported software counters long long id; @@ -230,20 +264,25 @@ bool PerfDriver::setup() { id = getTracepointId("irq/softirq_exit", &printb); if (id >= 0) { - setCounters(new PerfCounter(getCounters(), "Linux_irq_softirq", PERF_TYPE_TRACEPOINT, id, true)); + setCounters(new PerfCounter(getCounters(), "Linux_irq_softirq", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU)); } id = getTracepointId("irq/irq_handler_exit", &printb); if (id >= 0) { - setCounters(new PerfCounter(getCounters(), "Linux_irq_irq", PERF_TYPE_TRACEPOINT, id, true)); + setCounters(new PerfCounter(getCounters(), "Linux_irq_irq", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU)); } id = getTracepointId(SCHED_SWITCH, &printb); if (id >= 0) { - setCounters(new PerfCounter(getCounters(), "Linux_sched_switch", PERF_TYPE_TRACEPOINT, id, true)); + setCounters(new PerfCounter(getCounters(), "Linux_sched_switch", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU)); + } + + id = getTracepointId(CPU_FREQUENCY, &printb); + if (id >= 0) { + setCounters(new CPUFreqDriver(getCounters(), id)); } - setCounters(new PerfCounter(getCounters(), "Linux_cpu_wait_contention", TYPE_DERIVED, -1, false)); + setCounters(new PerfCounter(getCounters(), "Linux_cpu_wait_contention", TYPE_DERIVED, -1, 0, 0)); //Linux_cpu_wait_io @@ -254,7 +293,7 @@ bool PerfDriver::setup() { bool PerfDriver::summary(Buffer *const buffer) { struct utsname utsname; if (uname(&utsname) != 0) { - logg->logMessage("%s(%s:%i): uname failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("uname failed"); return false; } @@ -263,25 +302,26 @@ bool PerfDriver::summary(Buffer *const buffer) { struct timespec ts; if (clock_gettime(CLOCK_REALTIME, &ts) != 0) { - logg->logMessage("%s(%s:%i): clock_gettime failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("clock_gettime failed"); return false; } const int64_t timestamp = (int64_t)ts.tv_sec * NS_PER_S + ts.tv_nsec; const uint64_t monotonicStarted = getTime(); gSessionData->mMonotonicStarted = monotonicStarted; + const uint64_t currTime = 0;//getTime() - gSessionData->mMonotonicStarted; - buffer->summary(monotonicStarted, timestamp, monotonicStarted, monotonicStarted, buf); + buffer->summary(currTime, timestamp, monotonicStarted, monotonicStarted, buf); for (int i = 0; i < gSessionData->mCores; ++i) { - coreName(monotonicStarted, buffer, i); + coreName(currTime, buffer, i); } - buffer->commit(monotonicStarted); + buffer->commit(currTime); return true; } -void PerfDriver::coreName(const uint32_t startTime, Buffer *const buffer, const int cpu) { +void PerfDriver::coreName(const uint64_t currTime, Buffer *const buffer, const int cpu) { // Don't send information on a cpu we know nothing about if (gSessionData->mCpuIds[cpu] == -1) { return; @@ -293,8 +333,8 @@ void PerfDriver::coreName(const uint32_t startTime, Buffer *const buffer, const break; } } - if (gator_cpus[j].cpuid == gSessionData->mCpuIds[cpu]) { - buffer->coreName(startTime, cpu, gSessionData->mCpuIds[cpu], gator_cpus[j].core_name); + if (j < ARRAY_LENGTH(gator_cpus) && gator_cpus[j].cpuid == gSessionData->mCpuIds[cpu]) { + buffer->coreName(currTime, cpu, gSessionData->mCpuIds[cpu], gator_cpus[j].core_name); } else { char buf[32]; if (gSessionData->mCpuIds[cpu] == -1) { @@ -302,7 +342,7 @@ void PerfDriver::coreName(const uint32_t startTime, Buffer *const buffer, const } else { snprintf(buf, sizeof(buf), "Unknown (0x%.3x)", gSessionData->mCpuIds[cpu]); } - buffer->coreName(startTime, cpu, gSessionData->mCpuIds[cpu], buf); + buffer->coreName(currTime, cpu, gSessionData->mCpuIds[cpu], buf); } } @@ -325,8 +365,17 @@ void PerfDriver::setupCounter(Counter &counter) { bool PerfDriver::enable(const uint64_t currTime, PerfGroup *const group, Buffer *const buffer) const { for (PerfCounter *counter = static_cast(getCounters()); counter != NULL; counter = static_cast(counter->getNext())) { if (counter->isEnabled() && (counter->getType() != TYPE_DERIVED)) { - if (!group->add(currTime, 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)) { - logg->logMessage("%s(%s:%i): PerfGroup::add failed", __FUNCTION__, __FILE__, __LINE__); + int count = counter->getCount(); + uint64_t sampleType = counter->getSampleType(); + if (sampleType & PERF_SAMPLE_RAW) { + // If raw is enabled, every sample is needed + count = 1; + } + if (!group->add(currTime, buffer, counter->getKey(), counter->getType(), counter->getConfig(), count, + // use getCount instead of count as EBS counters need TID and IP but RAW tracepoints don't + (counter->getCount() > 0 ? PERF_SAMPLE_TID | PERF_SAMPLE_IP : 0) | sampleType, + counter->getFlags())) { + logg->logMessage("PerfGroup::add failed"); return false; } } @@ -335,15 +384,24 @@ bool PerfDriver::enable(const uint64_t currTime, PerfGroup *const group, Buffer return true; } +void PerfDriver::read(Buffer *const buffer, const int cpu) { + for (PerfCounter *counter = static_cast(getCounters()); counter != NULL; counter = static_cast(counter->getNext())) { + if (!counter->isEnabled()) { + continue; + } + counter->read(buffer, cpu); + } +} + long long PerfDriver::getTracepointId(const char *const name, DynBuf *const printb) { if (!printb->printf(EVENTS_PATH "/%s/id", name)) { - logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("DynBuf::printf failed"); return -1; } int64_t result; if (DriverSource::readInt64Driver(printb->getBuf(), &result) != 0) { - logg->logMessage("%s(%s:%i): DriverSource::readInt64Driver failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("DriverSource::readInt64Driver failed"); return -1; } diff --git a/tools/gator/daemon/PerfDriver.h b/tools/gator/daemon/PerfDriver.h index 846203a9e18b..95b42bfa30c0 100644 --- a/tools/gator/daemon/PerfDriver.h +++ b/tools/gator/daemon/PerfDriver.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -19,6 +19,7 @@ #define SCHED_SWITCH "sched/sched_switch" #define CPU_IDLE "power/cpu_idle" +#define CPU_FREQUENCY "power/cpu_frequency" class Buffer; class DynBuf; @@ -33,18 +34,19 @@ public: bool setup(); bool summary(Buffer *const buffer); - void coreName(const uint32_t startTime, Buffer *const buffer, const int cpu); + void coreName(const uint64_t currTime, Buffer *const buffer, const int cpu); bool isSetup() const { return mIsSetup; } void setupCounter(Counter &counter); bool enable(const uint64_t currTime, PerfGroup *const group, Buffer *const buffer) const; + void read(Buffer *const buffer, const int cpu); static long long getTracepointId(const char *const name, DynBuf *const printb); private: void addCpuCounters(const char *const counterName, const int type, const int numCounters); - void addUncoreCounters(const char *const counterName, const int type, const int numCounters); + void addUncoreCounters(const char *const counterName, const int type, const int numCounters, const bool hasCyclesCounter); bool mIsSetup; bool mLegacySupport; diff --git a/tools/gator/daemon/PerfGroup.cpp b/tools/gator/daemon/PerfGroup.cpp index 4fd960a9058c..cfc62e4cc77e 100644 --- a/tools/gator/daemon/PerfGroup.cpp +++ b/tools/gator/daemon/PerfGroup.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -16,17 +16,21 @@ #include #include "Buffer.h" +#include "DynBuf.h" #include "Logging.h" #include "Monitor.h" #include "PerfBuffer.h" #include "SessionData.h" +static const int schedSwitchKey = getEventKey(); +static const int clockKey = getEventKey(); + #define DEFAULT_PEA_ARGS(pea, additionalSampleType) \ pea.size = sizeof(pea); \ /* Emit time, read_format below, group leader id, and raw tracepoint info */ \ pea.sample_type = (gSessionData->perf.getLegacySupport() \ - ? PERF_SAMPLE_TID | PERF_SAMPLE_IP | PERF_SAMPLE_TIME | PERF_SAMPLE_READ | PERF_SAMPLE_ID \ - : PERF_SAMPLE_TIME | PERF_SAMPLE_READ | PERF_SAMPLE_IDENTIFIER ) | additionalSampleType; \ + ? PERF_SAMPLE_TID | PERF_SAMPLE_IP | PERF_SAMPLE_ID \ + : PERF_SAMPLE_IDENTIFIER ) | PERF_SAMPLE_TIME | additionalSampleType; \ /* Emit emit value in group format */ \ pea.read_format = PERF_FORMAT_ID | PERF_FORMAT_GROUP; \ /* start out disabled */ \ @@ -49,11 +53,12 @@ static int sys_perf_event_open(struct perf_event_attr *const attr, const pid_t p return fd; } -PerfGroup::PerfGroup(PerfBuffer *const pb) : mPb(pb) { +PerfGroup::PerfGroup(PerfBuffer *const pb) : mPb(pb), mSchedSwitchId(-1) { memset(&mAttrs, 0, sizeof(mAttrs)); - memset(&mPerCpu, 0, sizeof(mPerCpu)); + memset(&mFlags, 0, sizeof(mFlags)); memset(&mKeys, -1, sizeof(mKeys)); memset(&mFds, -1, sizeof(mFds)); + memset(&mLeaders, -1, sizeof(mLeaders)); } PerfGroup::~PerfGroup() { @@ -64,7 +69,7 @@ PerfGroup::~PerfGroup() { } } -bool PerfGroup::add(const uint64_t currTime, Buffer *const buffer, const int key, const __u32 type, const __u64 config, const __u64 sample, const __u64 sampleType, const int flags) { +int PerfGroup::doAdd(const uint64_t currTime, Buffer *const buffer, const int key, const __u32 type, const __u64 config, const __u64 sample, const __u64 sampleType, const int flags) { int i; for (i = 0; i < ARRAY_LENGTH(mKeys); ++i) { if (mKeys[i] < 0) { @@ -73,8 +78,8 @@ bool PerfGroup::add(const uint64_t currTime, Buffer *const buffer, const int key } if (i >= ARRAY_LENGTH(mKeys)) { - logg->logMessage("%s(%s:%i): Too many counters", __FUNCTION__, __FILE__, __LINE__); - return false; + logg->logMessage("Too many counters"); + return -1; } DEFAULT_PEA_ARGS(mAttrs[i], sampleType); @@ -82,121 +87,230 @@ bool PerfGroup::add(const uint64_t currTime, Buffer *const buffer, const int key mAttrs[i].config = config; mAttrs[i].sample_period = sample; // always be on the CPU but only a group leader can be pinned - mAttrs[i].pinned = (i == 0 ? 1 : 0); + mAttrs[i].pinned = (flags & PERF_GROUP_LEADER ? 1 : 0); mAttrs[i].mmap = (flags & PERF_GROUP_MMAP ? 1 : 0); mAttrs[i].comm = (flags & PERF_GROUP_COMM ? 1 : 0); mAttrs[i].freq = (flags & PERF_GROUP_FREQ ? 1 : 0); mAttrs[i].task = (flags & PERF_GROUP_TASK ? 1 : 0); mAttrs[i].sample_id_all = (flags & PERF_GROUP_SAMPLE_ID_ALL ? 1 : 0); - mPerCpu[i] = (flags & PERF_GROUP_PER_CPU); + mFlags[i] = flags; mKeys[i] = key; - buffer->pea(currTime, &mAttrs[i], key); + buffer->marshalPea(currTime, &mAttrs[i], key); + + return i; +} + +/* Counters from different hardware PMUs need to be in different + * groups. Software counters can be in the same group as the CPU and + * should be marked as PERF_GROUP_CPU. The big and little clusters can + * be in the same group as only one or the other will be available on + * a given CPU. + */ +int PerfGroup::getEffectiveType(const int type, const int flags) { + const int effectiveType = flags & PERF_GROUP_CPU ? (int)PERF_TYPE_HARDWARE : type; + if (effectiveType >= ARRAY_LENGTH(mLeaders)) { + logg->logError("perf type is too large, please increase the size of PerfGroup::mLeaders"); + handleException(); + } + return effectiveType; +} + +bool PerfGroup::createCpuGroup(const uint64_t currTime, Buffer *const buffer) { + if (mSchedSwitchId < 0) { + DynBuf b; + mSchedSwitchId = PerfDriver::getTracepointId(SCHED_SWITCH, &b); + if (mSchedSwitchId < 0) { + logg->logMessage("Unable to read sched_switch id"); + return false; + } + } + + mLeaders[PERF_TYPE_HARDWARE] = doAdd(currTime, buffer, schedSwitchKey, PERF_TYPE_TRACEPOINT, mSchedSwitchId, 1, PERF_SAMPLE_READ | PERF_SAMPLE_RAW, PERF_GROUP_MMAP | PERF_GROUP_COMM | PERF_GROUP_TASK | PERF_GROUP_SAMPLE_ID_ALL | PERF_GROUP_PER_CPU | PERF_GROUP_LEADER | PERF_GROUP_CPU); + if (mLeaders[PERF_TYPE_HARDWARE] < 0) { + return false; + } + + if (gSessionData->mSampleRate > 0 && !gSessionData->mIsEBS && doAdd(currTime, buffer, clockKey, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK, 1000000000UL / gSessionData->mSampleRate, PERF_SAMPLE_TID | PERF_SAMPLE_IP | PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU) < 0) { + return false; + } return true; } +bool PerfGroup::add(const uint64_t currTime, Buffer *const buffer, const int key, const __u32 type, const __u64 config, const __u64 sample, const __u64 sampleType, const int flags) { + const int effectiveType = getEffectiveType(type, flags); + + // Does a group exist for this already? + if (!(flags & PERF_GROUP_LEADER) && mLeaders[effectiveType] < 0) { + // Create it + if (effectiveType == PERF_TYPE_HARDWARE) { + if (!createCpuGroup(currTime, buffer)) { + return false; + } + } else { + // Non-CPU PMUs are sampled every 100ms for Sample Rate: None and EBS, otherwise they would never be sampled + const uint64_t timeout = gSessionData->mSampleRate > 0 && !gSessionData->mIsEBS ? 1000000000UL / gSessionData->mSampleRate : 100000000UL; + // PERF_SAMPLE_TID | PERF_SAMPLE_IP aren't helpful on non-CPU or 'uncore' PMUs - which CPU is the right one to sample? But removing it causes problems, remove it later. + mLeaders[effectiveType] = doAdd(currTime, buffer, clockKey, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK, timeout, PERF_SAMPLE_TID | PERF_SAMPLE_IP | PERF_SAMPLE_READ, PERF_GROUP_LEADER); + if (mLeaders[effectiveType] < 0) { + return false; + } + } + } + + if (!(flags & PERF_GROUP_LEADER) && effectiveType != PERF_TYPE_HARDWARE && (flags & PERF_GROUP_PER_CPU)) { + logg->logError("'uncore' counters are not permitted to be per-cpu"); + handleException(); + } + + return doAdd(currTime, buffer, key, type, config, sample, sampleType, flags) >= 0; +} + int PerfGroup::prepareCPU(const int cpu, Monitor *const monitor) { - logg->logMessage("%s(%s:%i): Onlining cpu %i", __FUNCTION__, __FILE__, __LINE__, cpu); + logg->logMessage("Onlining cpu %i", cpu); for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) { if (mKeys[i] < 0) { continue; } - if ((cpu != 0) && !mPerCpu[i]) { + if ((cpu != 0) && !(mFlags[i] & PERF_GROUP_PER_CPU)) { continue; } - const int offset = i * gSessionData->mCores; - if (mFds[cpu + offset] >= 0) { - logg->logMessage("%s(%s:%i): cpu already online or not correctly cleaned up", __FUNCTION__, __FILE__, __LINE__); + const int offset = i * gSessionData->mCores + cpu; + if (mFds[offset] >= 0) { + logg->logMessage("cpu already online or not correctly cleaned up"); return PG_FAILURE; } - 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); - mFds[cpu + offset] = sys_perf_event_open(&mAttrs[i], -1, cpu, i == 0 ? -1 : mFds[cpu], i == 0 ? 0 : PERF_FLAG_FD_OUTPUT); - if (mFds[cpu + offset] < 0) { - logg->logMessage("%s(%s:%i): failed %s", __FUNCTION__, __FILE__, __LINE__, strerror(errno)); + logg->logMessage("perf_event_open cpu: %i type: %i config: %lli sample: %lli sample_type: 0x%llx pinned: %lli mmap: %lli comm: %lli freq: %lli task: %lli sample_id_all: %lli", cpu, mAttrs[i].type, mAttrs[i].config, mAttrs[i].sample_period, mAttrs[i].sample_type, mAttrs[i].pinned, mAttrs[i].mmap, mAttrs[i].comm, mAttrs[i].freq, mAttrs[i].task, mAttrs[i].sample_id_all); + mFds[offset] = sys_perf_event_open(&mAttrs[i], -1, cpu, mAttrs[i].pinned ? -1 : mFds[mLeaders[getEffectiveType(mAttrs[i].type, mFlags[i])] * gSessionData->mCores + cpu], mAttrs[i].pinned ? 0 : PERF_FLAG_FD_OUTPUT); + if (mFds[offset] < 0) { + logg->logMessage("failed %s", strerror(errno)); if (errno == ENODEV) { + // The core is offline return PG_CPU_OFFLINE; } +#ifndef USE_STRICTER_CHECK continue; +#else + if (errno == ENOENT) { + // This event doesn't apply to this CPU but should apply to a different one, ex bL + continue; + } + logg->logMessage("perf_event_open failed"); + return PG_FAILURE; +#endif } - if (!mPb->useFd(cpu, mFds[cpu + offset])) { - logg->logMessage("%s(%s:%i): PerfBuffer::useFd failed", __FUNCTION__, __FILE__, __LINE__); + if (!mPb->useFd(cpu, mFds[offset])) { + logg->logMessage("PerfBuffer::useFd failed"); return PG_FAILURE; } - if (!monitor->add(mFds[cpu + offset])) { - logg->logMessage("%s(%s:%i): Monitor::add failed", __FUNCTION__, __FILE__, __LINE__); - return PG_FAILURE; + if (!monitor->add(mFds[offset])) { + logg->logMessage("Monitor::add failed"); + return PG_FAILURE; } } return PG_SUCCESS; } -int PerfGroup::onlineCPU(const uint64_t currTime, const int cpu, const bool start, Buffer *const buffer) { - __u64 ids[ARRAY_LENGTH(mKeys)]; - int coreKeys[ARRAY_LENGTH(mKeys)]; - int idCount = 0; +static bool readAndSend(const uint64_t currTime, Buffer *const buffer, const int fd, const int keyCount, const int *const keys) { + char buf[1024]; + ssize_t bytes = read(fd, buf, sizeof(buf)); + if (bytes < 0) { + logg->logMessage("read failed"); + return false; + } + buffer->marshalKeysOld(currTime, keyCount, keys, bytes, buf); - for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) { - const int fd = mFds[cpu + i * gSessionData->mCores]; - if (fd < 0) { - continue; - } + return true; +} - coreKeys[idCount] = mKeys[i]; - if (!gSessionData->perf.getLegacySupport() && ioctl(fd, PERF_EVENT_IOC_ID, &ids[idCount]) != 0 && - // Workaround for running 32-bit gatord on 64-bit systems, kernel patch in the works - ioctl(fd, (PERF_EVENT_IOC_ID & ~IOCSIZE_MASK) | (8 << _IOC_SIZESHIFT), &ids[idCount]) != 0) { - logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__); - return 0; - } - ++idCount; - } +int PerfGroup::onlineCPU(const uint64_t currTime, const int cpu, const bool enable, Buffer *const buffer) { + bool addedEvents = false; if (!gSessionData->perf.getLegacySupport()) { - buffer->keys(currTime, idCount, ids, coreKeys); + int idCount = 0; + int coreKeys[ARRAY_LENGTH(mKeys)]; + __u64 ids[ARRAY_LENGTH(mKeys)]; + + for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) { + const int fd = mFds[cpu + i * gSessionData->mCores]; + if (fd < 0) { + continue; + } + + coreKeys[idCount] = mKeys[i]; + if (ioctl(fd, PERF_EVENT_IOC_ID, &ids[idCount]) != 0 && + // Workaround for running 32-bit gatord on 64-bit systems, kernel patch in the works + ioctl(fd, (PERF_EVENT_IOC_ID & ~IOCSIZE_MASK) | (8 << _IOC_SIZESHIFT), &ids[idCount]) != 0) { + logg->logMessage("ioctl failed"); + return 0; + } + ++idCount; + addedEvents = true; + } + + buffer->marshalKeys(currTime, idCount, ids, coreKeys); } else { - char buf[1024]; - ssize_t bytes = read(mFds[cpu], buf, sizeof(buf)); - if (bytes < 0) { - logg->logMessage("read failed"); - return 0; + int idCounts[ARRAY_LENGTH(mLeaders)] = { 0 }; + int coreKeys[ARRAY_LENGTH(mLeaders)][ARRAY_LENGTH(mKeys)]; + for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) { + const int fd = mFds[cpu + i * gSessionData->mCores]; + if (fd < 0) { + continue; + } + + const int effectiveType = getEffectiveType(mAttrs[i].type, mFlags[i]); + if (mAttrs[i].pinned && mLeaders[effectiveType] != i) { + if (!readAndSend(currTime, buffer, fd, 1, mKeys + i)) { + return 0; + } + } else { + coreKeys[effectiveType][idCounts[effectiveType]] = mKeys[i]; + ++idCounts[effectiveType]; + addedEvents = true; + } + } + + for (int i = 0; i < ARRAY_LENGTH(mLeaders); ++i) { + if (idCounts[i] > 0 && !readAndSend(currTime, buffer, mFds[mLeaders[i] * gSessionData->mCores + cpu], idCounts[i], coreKeys[i])) { + return 0; + } } - buffer->keysOld(currTime, idCount, coreKeys, bytes, buf); } - if (start) { + if (enable) { for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) { int offset = i * gSessionData->mCores + cpu; if (mFds[offset] >= 0 && ioctl(mFds[offset], PERF_EVENT_IOC_ENABLE, 0) < 0) { - logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("ioctl failed"); return 0; } } } - if (idCount == 0) { - logg->logMessage("%s(%s:%i): no events came online", __FUNCTION__, __FILE__, __LINE__); + if (!addedEvents) { + logg->logMessage("no events came online"); } - return idCount; + return 1; } bool PerfGroup::offlineCPU(const int cpu) { - logg->logMessage("%s(%s:%i): Offlining cpu %i", __FUNCTION__, __FILE__, __LINE__, cpu); + logg->logMessage("Offlining cpu %i", cpu); - for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) { + for (int i = ARRAY_LENGTH(mKeys) - 1; i >= 0; --i) { int offset = i * gSessionData->mCores + cpu; if (mFds[offset] >= 0 && ioctl(mFds[offset], PERF_EVENT_IOC_DISABLE, 0) < 0) { - logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("ioctl failed"); return false; } } @@ -204,7 +318,7 @@ bool PerfGroup::offlineCPU(const int cpu) { // Mark the buffer so that it will be released next time it's read mPb->discard(cpu); - for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) { + for (int i = ARRAY_LENGTH(mKeys) - 1; i >= 0; --i) { if (mKeys[i] < 0) { continue; } @@ -222,7 +336,7 @@ bool PerfGroup::offlineCPU(const int cpu) { bool PerfGroup::start() { for (int pos = 0; pos < ARRAY_LENGTH(mFds); ++pos) { if (mFds[pos] >= 0 && ioctl(mFds[pos], PERF_EVENT_IOC_ENABLE, 0) < 0) { - logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("ioctl failed"); goto fail; } } diff --git a/tools/gator/daemon/PerfGroup.h b/tools/gator/daemon/PerfGroup.h index f7b3d725bac7..f30d3a6a9c68 100644 --- a/tools/gator/daemon/PerfGroup.h +++ b/tools/gator/daemon/PerfGroup.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -27,6 +27,8 @@ enum PerfGroupFlags { PERF_GROUP_TASK = 1 << 3, PERF_GROUP_SAMPLE_ID_ALL = 1 << 4, PERF_GROUP_PER_CPU = 1 << 5, + PERF_GROUP_LEADER = 1 << 6, + PERF_GROUP_CPU = 1 << 7, }; enum { @@ -40,22 +42,29 @@ public: PerfGroup(PerfBuffer *const pb); ~PerfGroup(); + bool createCpuGroup(const uint64_t currTime, Buffer *const buffer); bool add(const uint64_t currTime, Buffer *const buffer, const int key, const __u32 type, const __u64 config, const __u64 sample, const __u64 sampleType, const int flags); // Safe to call concurrently int prepareCPU(const int cpu, Monitor *const monitor); // Not safe to call concurrently. Returns the number of events enabled - int onlineCPU(const uint64_t currTime, const int cpu, const bool start, Buffer *const buffer); + int onlineCPU(const uint64_t currTime, const int cpu, const bool enable, Buffer *const buffer); bool offlineCPU(int cpu); bool start(); void stop(); private: - // +1 for the group leader - struct perf_event_attr mAttrs[MAX_PERFORMANCE_COUNTERS + 1]; - bool mPerCpu[MAX_PERFORMANCE_COUNTERS + 1]; - int mKeys[MAX_PERFORMANCE_COUNTERS + 1]; - int mFds[NR_CPUS * (MAX_PERFORMANCE_COUNTERS + 1)]; + int getEffectiveType(const int type, const int flags); + int doAdd(const uint64_t currTime, Buffer *const buffer, const int key, const __u32 type, const __u64 config, const __u64 sample, const __u64 sampleType, const int flags); + + // 2* to be conservative for sched_switch, cpu_idle, hrtimer and non-CPU groups + struct perf_event_attr mAttrs[2*MAX_PERFORMANCE_COUNTERS]; PerfBuffer *const mPb; + int mFlags[2*MAX_PERFORMANCE_COUNTERS]; + int mKeys[2*MAX_PERFORMANCE_COUNTERS]; + int mFds[NR_CPUS * (2*MAX_PERFORMANCE_COUNTERS)]; + // Offset in mAttrs, mFlags and mKeys of the group leaders for each perf type + int mLeaders[16]; + int mSchedSwitchId; // Intentionally undefined PerfGroup(const PerfGroup &); diff --git a/tools/gator/daemon/PerfSource.cpp b/tools/gator/daemon/PerfSource.cpp index 193b7789a290..2c45de8e06e9 100644 --- a/tools/gator/daemon/PerfSource.cpp +++ b/tools/gator/daemon/PerfSource.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -31,16 +31,18 @@ extern Child *child; +static const int cpuIdleKey = getEventKey(); + static bool sendTracepointFormat(const uint64_t currTime, Buffer *const buffer, const char *const name, DynBuf *const printb, DynBuf *const b) { if (!printb->printf(EVENTS_PATH "/%s/format", name)) { - logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("DynBuf::printf failed"); return false; } if (!b->read(printb->getBuf())) { - logg->logMessage("%s(%s:%i): DynBuf::read failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("DynBuf::read failed"); return false; } - buffer->format(currTime, b->getLength(), b->getBuf()); + buffer->marshalFormat(currTime, b->getLength(), b->getBuf()); return true; } @@ -58,18 +60,18 @@ static void *syncFunc(void *arg) { sigset_t set; if (sigfillset(&set) != 0) { - logg->logError(__FILE__, __LINE__, "sigfillset failed"); + logg->logError("sigfillset failed"); handleException(); } if ((err = pthread_sigmask(SIG_SETMASK, &set, NULL)) != 0) { - logg->logError(__FILE__, __LINE__, "pthread_sigmask failed"); + logg->logError("pthread_sigmask failed"); handleException(); } } for (;;) { if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts) != 0) { - logg->logError(__FILE__, __LINE__, "clock_gettime failed"); + logg->logError("clock_gettime failed"); handleException(); } const int64_t currTime = ts.tv_sec * NS_PER_S + ts.tv_nsec; @@ -95,7 +97,7 @@ static void *syncFunc(void *arg) static long getMaxCoreNum() { DIR *dir = opendir("/sys/devices/system/cpu"); if (dir == NULL) { - logg->logError(__FILE__, __LINE__, "Unable to determine the number of cores on the target, opendir failed"); + logg->logError("Unable to determine the number of cores on the target, opendir failed"); handleException(); } @@ -114,22 +116,22 @@ static long getMaxCoreNum() { closedir(dir); if (maxCoreNum < 1) { - logg->logError(__FILE__, __LINE__, "Unable to determine the number of cores on the target, no cpu# directories found"); + logg->logError("Unable to determine the number of cores on the target, no cpu# directories found"); handleException(); } if (maxCoreNum >= NR_CPUS) { - logg->logError(__FILE__, __LINE__, "Too many cores on the target, please increase NR_CPUS in Config.h"); + logg->logError("Too many cores on the target, please increase NR_CPUS in Config.h"); handleException(); } return maxCoreNum; } -PerfSource::PerfSource(sem_t *senderSem, sem_t *startProfile) : mSummary(0, FRAME_SUMMARY, 1024, senderSem), mBuffer(0, FRAME_PERF_ATTRS, 1024*1024, senderSem), mCountersBuf(), mCountersGroup(&mCountersBuf), mIdleGroup(&mCountersBuf), mMonitor(), mUEvent(), mSenderSem(senderSem), mStartProfile(startProfile), mInterruptFd(-1), mIsDone(false) { +PerfSource::PerfSource(sem_t *senderSem, sem_t *startProfile) : mSummary(0, FRAME_SUMMARY, 1024, senderSem), mBuffer(NULL), mCountersBuf(), mCountersGroup(&mCountersBuf), mMonitor(), mUEvent(), mSenderSem(senderSem), mStartProfile(startProfile), mInterruptFd(-1), mIsDone(false) { long l = sysconf(_SC_PAGE_SIZE); if (l < 0) { - logg->logError(__FILE__, __LINE__, "Unable to obtain the page size"); + logg->logError("Unable to obtain the page size"); handleException(); } gSessionData->mPageSize = static_cast(l); @@ -137,15 +139,18 @@ PerfSource::PerfSource(sem_t *senderSem, sem_t *startProfile) : mSummary(0, FRAM } PerfSource::~PerfSource() { + delete mBuffer; } bool PerfSource::prepare() { DynBuf printb; DynBuf b1; - long long schedSwitchId; long long cpuIdleId; - const uint64_t currTime = getTime(); + // MonotonicStarted has not yet been assigned! + const uint64_t currTime = 0;//getTime() - gSessionData->mMonotonicStarted; + + mBuffer = new Buffer(0, FRAME_PERF_ATTRS, gSessionData->mTotalBufferSize*1024*1024, mSenderSem); // Reread cpuinfo since cores may have changed since startup gSessionData->readCpuInfo(); @@ -155,72 +160,59 @@ bool PerfSource::prepare() { || !mUEvent.init() || !mMonitor.add(mUEvent.getFd()) - || (schedSwitchId = PerfDriver::getTracepointId(SCHED_SWITCH, &printb)) < 0 - || !sendTracepointFormat(currTime, &mBuffer, SCHED_SWITCH, &printb, &b1) + || !sendTracepointFormat(currTime, mBuffer, SCHED_SWITCH, &printb, &b1) || (cpuIdleId = PerfDriver::getTracepointId(CPU_IDLE, &printb)) < 0 - || !sendTracepointFormat(currTime, &mBuffer, CPU_IDLE, &printb, &b1) + || !sendTracepointFormat(currTime, mBuffer, CPU_IDLE, &printb, &b1) - // Only want RAW but not IP on sched_switch and don't want TID on SAMPLE_ID - || !mCountersGroup.add(currTime, &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) - || !mIdleGroup.add(currTime, &mBuffer, 101/**/, PERF_TYPE_TRACEPOINT, cpuIdleId, 1, PERF_SAMPLE_RAW, PERF_GROUP_PER_CPU) + || !sendTracepointFormat(currTime, mBuffer, CPU_FREQUENCY, &printb, &b1) - // Only want TID and IP but not RAW on timer - || (gSessionData->mSampleRate > 0 && !gSessionData->mIsEBS && !mCountersGroup.add(currTime, &mBuffer, 102/**/, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK, 1000000000UL / gSessionData->mSampleRate, PERF_SAMPLE_TID | PERF_SAMPLE_IP, PERF_GROUP_PER_CPU)) + || !mCountersGroup.createCpuGroup(currTime, mBuffer) + || !mCountersGroup.add(currTime, mBuffer, cpuIdleKey, PERF_TYPE_TRACEPOINT, cpuIdleId, 1, PERF_SAMPLE_RAW, PERF_GROUP_LEADER | PERF_GROUP_PER_CPU) - || !gSessionData->perf.enable(currTime, &mCountersGroup, &mBuffer) + || !gSessionData->perf.enable(currTime, &mCountersGroup, mBuffer) || 0) { - logg->logMessage("%s(%s:%i): perf setup failed, are you running Linux 3.4 or later?", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("perf setup failed, are you running Linux 3.4 or later?"); return false; } for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) { const int result = mCountersGroup.prepareCPU(cpu, &mMonitor); if ((result != PG_SUCCESS) && (result != PG_CPU_OFFLINE)) { - logg->logError(__FILE__, __LINE__, "PerfGroup::prepareCPU on mCountersGroup failed"); - handleException(); - } - } - for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) { - const int result = mIdleGroup.prepareCPU(cpu, &mMonitor); - if ((result != PG_SUCCESS) && (result != PG_CPU_OFFLINE)) { - logg->logError(__FILE__, __LINE__, "PerfGroup::prepareCPU on mIdleGroup failed"); + logg->logError("PerfGroup::prepareCPU on mCountersGroup failed"); handleException(); } } int numEvents = 0; for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) { - numEvents += mCountersGroup.onlineCPU(currTime, cpu, false, &mBuffer); - } - for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) { - numEvents += mIdleGroup.onlineCPU(currTime, cpu, false, &mBuffer); + numEvents += mCountersGroup.onlineCPU(currTime, cpu, false, mBuffer); } if (numEvents <= 0) { - logg->logMessage("%s(%s:%i): PerfGroup::onlineCPU failed on all cores", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("PerfGroup::onlineCPU failed on all cores"); return false; } // Send the summary right before the start so that the monotonic delta is close to the start time if (!gSessionData->perf.summary(&mSummary)) { - logg->logError(__FILE__, __LINE__, "PerfDriver::summary failed", __FUNCTION__, __FILE__, __LINE__); - handleException(); + logg->logError("PerfDriver::summary failed"); + handleException(); } // Start the timer thread to used to sync perf and monotonic raw times pthread_t syncThread; if (pthread_create(&syncThread, NULL, syncFunc, NULL)) { - logg->logError(__FILE__, __LINE__, "pthread_create failed", __FUNCTION__, __FILE__, __LINE__); - handleException(); + logg->logError("pthread_create failed"); + handleException(); } struct sched_param param; param.sched_priority = sched_get_priority_max(SCHED_FIFO); if (pthread_setschedparam(syncThread, SCHED_FIFO | SCHED_RESET_ON_FORK, ¶m) != 0) { - logg->logError(__FILE__, __LINE__, "pthread_setschedparam failed"); - handleException(); + logg->logError("pthread_setschedparam failed"); + handleException(); } - mBuffer.commit(currTime); + mBuffer->commit(currTime); return true; } @@ -240,18 +232,17 @@ void *procFunc(void *arg) { // Gator runs at a high priority, reset the priority to the default if (setpriority(PRIO_PROCESS, syscall(__NR_gettid), 0) == -1) { - logg->logError(__FILE__, __LINE__, "setpriority failed"); + logg->logError("setpriority failed"); handleException(); } if (!readProcMaps(args->mCurrTime, args->mBuffer, &printb, &b)) { - logg->logError(__FILE__, __LINE__, "readProcMaps failed"); + logg->logError("readProcMaps failed"); handleException(); } - args->mBuffer->commit(args->mCurrTime); if (!readKallsyms(args->mCurrTime, args->mBuffer, &args->mIsDone)) { - logg->logError(__FILE__, __LINE__, "readKallsyms failed"); + logg->logError("readKallsyms failed"); handleException(); } args->mBuffer->commit(args->mCurrTime); @@ -266,67 +257,72 @@ void PerfSource::run() { pthread_t procThread; ProcThreadArgs procThreadArgs; + if (pipe_cloexec(pipefd) != 0) { + logg->logError("pipe failed"); + handleException(); + } + mInterruptFd = pipefd[1]; + + if (!mMonitor.add(pipefd[0])) { + logg->logError("Monitor::add failed"); + handleException(); + } + { DynBuf printb; DynBuf b1; DynBuf b2; - const uint64_t currTime = getTime(); + const uint64_t currTime = getTime() - gSessionData->mMonotonicStarted; // Start events before reading proc to avoid race conditions - if (!mCountersGroup.start() || !mIdleGroup.start()) { - logg->logError(__FILE__, __LINE__, "PerfGroup::start failed", __FUNCTION__, __FILE__, __LINE__); + if (!mCountersGroup.start()) { + logg->logError("PerfGroup::start failed"); handleException(); } - if (!readProcComms(currTime, &mBuffer, &printb, &b1, &b2)) { - logg->logError(__FILE__, __LINE__, "readProcComms failed"); + mBuffer->perfCounterHeader(currTime); + for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) { + gSessionData->perf.read(mBuffer, cpu); + } + mBuffer->perfCounterFooter(currTime); + + if (!readProcComms(currTime, mBuffer, &printb, &b1, &b2)) { + logg->logError("readProcComms failed"); handleException(); } - mBuffer.commit(currTime); + mBuffer->commit(currTime); // Postpone reading kallsyms as on android adb gets too backed up and data is lost - procThreadArgs.mBuffer = &mBuffer; + procThreadArgs.mBuffer = mBuffer; procThreadArgs.mCurrTime = currTime; procThreadArgs.mIsDone = false; if (pthread_create(&procThread, NULL, procFunc, &procThreadArgs)) { - logg->logError(__FILE__, __LINE__, "pthread_create failed", __FUNCTION__, __FILE__, __LINE__); + logg->logError("pthread_create failed"); handleException(); } } - if (pipe_cloexec(pipefd) != 0) { - logg->logError(__FILE__, __LINE__, "pipe failed"); - handleException(); - } - mInterruptFd = pipefd[1]; - - if (!mMonitor.add(pipefd[0])) { - logg->logError(__FILE__, __LINE__, "Monitor::add failed"); - handleException(); - } - - int timeout = -1; - if (gSessionData->mLiveRate > 0) { - timeout = gSessionData->mLiveRate/NS_PER_MS; - } - sem_post(mStartProfile); + const uint64_t NO_RATE = ~0ULL; + const uint64_t rate = gSessionData->mLiveRate > 0 && gSessionData->mSampleRate > 0 ? gSessionData->mLiveRate : NO_RATE; + uint64_t nextTime = 0; + int timeout = rate != NO_RATE ? 0 : -1; while (gSessionData->mSessionIsActive) { // +1 for uevents, +1 for pipe struct epoll_event events[NR_CPUS + 2]; int ready = mMonitor.wait(events, ARRAY_LENGTH(events), timeout); if (ready < 0) { - logg->logError(__FILE__, __LINE__, "Monitor::wait failed"); + logg->logError("Monitor::wait failed"); handleException(); } - const uint64_t currTime = getTime(); + const uint64_t currTime = getTime() - gSessionData->mMonotonicStarted; for (int i = 0; i < ready; ++i) { if (events[i].data.fd == mUEvent.getFd()) { if (!handleUEvent(currTime)) { - logg->logError(__FILE__, __LINE__, "PerfSource::handleUEvent failed"); + logg->logError("PerfSource::handleUEvent failed"); handleException(); } break; @@ -337,18 +333,24 @@ void PerfSource::run() { sem_post(mSenderSem); // In one shot mode, stop collection once all the buffers are filled - // Assume timeout == 0 in this case - if (gSessionData->mOneShot && gSessionData->mSessionIsActive) { - logg->logMessage("%s(%s:%i): One shot", __FUNCTION__, __FILE__, __LINE__); + if (gSessionData->mOneShot && gSessionData->mSessionIsActive && ((mSummary.bytesAvailable() <= 0) || (mBuffer->bytesAvailable() <= 0) || mCountersBuf.isFull())) { + logg->logMessage("One shot (perf)"); child->endSession(); } + + if (rate != NO_RATE) { + while (currTime > nextTime) { + nextTime += rate; + } + // + NS_PER_MS - 1 to ensure always rounding up + timeout = max(0, (int)((nextTime + NS_PER_MS - 1 - getTime() + gSessionData->mMonotonicStarted)/NS_PER_MS)); + } } procThreadArgs.mIsDone = true; pthread_join(procThread, NULL); - mIdleGroup.stop(); mCountersGroup.stop(); - mBuffer.setDone(); + mBuffer->setDone(); mIsDone = true; // send a notification that data is ready @@ -362,57 +364,53 @@ void PerfSource::run() { bool PerfSource::handleUEvent(const uint64_t currTime) { UEventResult result; if (!mUEvent.read(&result)) { - logg->logMessage("%s(%s:%i): UEvent::Read failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("UEvent::Read failed"); return false; } if (strcmp(result.mSubsystem, "cpu") == 0) { if (strncmp(result.mDevPath, CPU_DEVPATH, sizeof(CPU_DEVPATH) - 1) != 0) { - logg->logMessage("%s(%s:%i): Unexpected cpu DEVPATH format", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("Unexpected cpu DEVPATH format"); return false; } char *endptr; errno = 0; int cpu = strtol(result.mDevPath + sizeof(CPU_DEVPATH) - 1, &endptr, 10); if (errno != 0 || *endptr != '\0') { - logg->logMessage("%s(%s:%i): strtol failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("strtol failed"); return false; } if (cpu >= gSessionData->mCores) { - logg->logError(__FILE__, __LINE__, "Only %i cores are expected but core %i reports %s", gSessionData->mCores, cpu, result.mAction); + logg->logError("Only %i cores are expected but core %i reports %s", gSessionData->mCores, cpu, result.mAction); handleException(); } if (strcmp(result.mAction, "online") == 0) { - mBuffer.onlineCPU(currTime, currTime - gSessionData->mMonotonicStarted, cpu); + mBuffer->onlineCPU(currTime, cpu); // Only call onlineCPU if prepareCPU succeeded - bool result = false; + bool ret = false; int err = mCountersGroup.prepareCPU(cpu, &mMonitor); if (err == PG_CPU_OFFLINE) { - result = true; + ret = true; } else if (err == PG_SUCCESS) { - if (mCountersGroup.onlineCPU(currTime, cpu, true, &mBuffer)) { - err = mIdleGroup.prepareCPU(cpu, &mMonitor); - if (err == PG_CPU_OFFLINE) { - result = true; - } else if (err == PG_SUCCESS) { - if (mIdleGroup.onlineCPU(currTime, cpu, true, &mBuffer)) { - result = true; - } - } + if (mCountersGroup.onlineCPU(currTime, cpu, true, mBuffer) > 0) { + mBuffer->perfCounterHeader(currTime); + gSessionData->perf.read(mBuffer, cpu); + mBuffer->perfCounterFooter(currTime); + ret = true; } } - mBuffer.commit(currTime); + mBuffer->commit(currTime); gSessionData->readCpuInfo(); gSessionData->perf.coreName(currTime, &mSummary, cpu); mSummary.commit(currTime); - return result; + return ret; } else if (strcmp(result.mAction, "offline") == 0) { - const bool result = mCountersGroup.offlineCPU(cpu) && mIdleGroup.offlineCPU(cpu); - mBuffer.offlineCPU(currTime, currTime - gSessionData->mMonotonicStarted, cpu); - return result; + const bool ret = mCountersGroup.offlineCPU(cpu); + mBuffer->offlineCPU(currTime, cpu); + return ret; } } @@ -424,14 +422,14 @@ void PerfSource::interrupt() { int8_t c = 0; // Write to the pipe to wake the monitor which will cause mSessionIsActive to be reread if (::write(mInterruptFd, &c, sizeof(c)) != sizeof(c)) { - logg->logError(__FILE__, __LINE__, "write failed"); + logg->logError("write failed"); handleException(); } } } bool PerfSource::isDone () { - return mBuffer.isDone() && mIsDone && mCountersBuf.isEmpty(); + return mBuffer->isDone() && mIsDone && mCountersBuf.isEmpty(); } void PerfSource::write (Sender *sender) { @@ -439,11 +437,11 @@ void PerfSource::write (Sender *sender) { mSummary.write(sender); gSessionData->mSentSummary = true; } - if (!mBuffer.isDone()) { - mBuffer.write(sender); + if (!mBuffer->isDone()) { + mBuffer->write(sender); } if (!mCountersBuf.send(sender)) { - logg->logError(__FILE__, __LINE__, "PerfBuffer::send failed"); + logg->logError("PerfBuffer::send failed"); handleException(); } } diff --git a/tools/gator/daemon/PerfSource.h b/tools/gator/daemon/PerfSource.h index ce1eafe8e953..feec1c269922 100644 --- a/tools/gator/daemon/PerfSource.h +++ b/tools/gator/daemon/PerfSource.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -36,10 +36,9 @@ private: bool handleUEvent(const uint64_t currTime); Buffer mSummary; - Buffer mBuffer; + Buffer *mBuffer; PerfBuffer mCountersBuf; PerfGroup mCountersGroup; - PerfGroup mIdleGroup; Monitor mMonitor; UEvent mUEvent; sem_t *const mSenderSem; diff --git a/tools/gator/daemon/Proc.cpp b/tools/gator/daemon/Proc.cpp index e6b26b1199fa..4ba59b632836 100644 --- a/tools/gator/daemon/Proc.cpp +++ b/tools/gator/daemon/Proc.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -31,20 +31,20 @@ struct ProcStat { static bool readProcStat(ProcStat *const ps, const char *const pathname, DynBuf *const b) { if (!b->read(pathname)) { - logg->logMessage("%s(%s:%i): DynBuf::read failed, likely because the thread exited", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("DynBuf::read failed, likely because the thread exited"); // This is not a fatal error - the thread just doesn't exist any more return true; } char *comm = strchr(b->getBuf(), '('); if (comm == NULL) { - logg->logMessage("%s(%s:%i): parsing stat failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("parsing stat failed"); return false; } ++comm; char *const str = strrchr(comm, ')'); if (str == NULL) { - logg->logMessage("%s(%s:%i): parsing stat failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("parsing stat failed"); return false; } *str = '\0'; @@ -53,7 +53,7 @@ static bool readProcStat(ProcStat *const ps, const char *const pathname, DynBuf 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); if (count != 1) { - logg->logMessage("%s(%s:%i): sscanf failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("sscanf failed"); return false; } @@ -65,7 +65,7 @@ static const char APP_PROCESS[] = "app_process"; static const char *readProcExe(DynBuf *const printb, const int pid, const int tid, DynBuf *const b) { if (tid == -1 ? !printb->printf("/proc/%i/exe", pid) : !printb->printf("/proc/%i/task/%i/exe", pid, tid)) { - logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("DynBuf::printf failed"); return NULL; } @@ -82,7 +82,7 @@ static const char *readProcExe(DynBuf *const printb, const int pid, const int ti // readlink /proc/[pid]/exe returns ENOENT for kernel threads image = "\0"; } else { - logg->logMessage("%s(%s:%i): DynBuf::readlink failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("DynBuf::readlink failed"); return NULL; } @@ -94,12 +94,12 @@ static const char *readProcExe(DynBuf *const printb, const int pid, const int ti if (tid == -1 ? !printb->printf("/proc/%i/cmdline", pid) : !printb->printf("/proc/%i/task/%i/cmdline", pid, tid)) { - logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("DynBuf::printf failed"); return NULL; } if (!b->read(printb->getBuf())) { - logg->logMessage("%s(%s:%i): DynBuf::read failed, likely because the thread exited", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("DynBuf::read failed, likely because the thread exited"); return NULL; } @@ -110,12 +110,12 @@ static bool readProcTask(const uint64_t currTime, Buffer *const buffer, const in bool result = false; if (!b1->printf("/proc/%i/task", pid)) { - logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("DynBuf::printf failed"); return result; } DIR *task = opendir(b1->getBuf()); if (task == NULL) { - logg->logMessage("%s(%s:%i): opendir failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("opendir failed"); // This is not a fatal error - the thread just doesn't exist any more return true; } @@ -130,22 +130,22 @@ static bool readProcTask(const uint64_t currTime, Buffer *const buffer, const in } if (!printb->printf("/proc/%i/task/%i/stat", pid, tid)) { - logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("DynBuf::printf failed"); goto fail; } ProcStat ps; if (!readProcStat(&ps, printb->getBuf(), b1)) { - logg->logMessage("%s(%s:%i): readProcStat failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("readProcStat failed"); goto fail; } const char *const image = readProcExe(printb, pid, tid, b2); if (image == NULL) { - logg->logMessage("%s(%s:%i): readImage failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("readImage failed"); goto fail; } - buffer->comm(currTime, pid, tid, image, ps.comm); + buffer->marshalComm(currTime, pid, tid, image, ps.comm); } result = true; @@ -161,7 +161,7 @@ bool readProcComms(const uint64_t currTime, Buffer *const buffer, DynBuf *const DIR *proc = opendir("/proc"); if (proc == NULL) { - logg->logMessage("%s(%s:%i): opendir failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("opendir failed"); return result; } @@ -175,26 +175,26 @@ bool readProcComms(const uint64_t currTime, Buffer *const buffer, DynBuf *const } if (!printb->printf("/proc/%i/stat", pid)) { - logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("DynBuf::printf failed"); goto fail; } ProcStat ps; if (!readProcStat(&ps, printb->getBuf(), b1)) { - logg->logMessage("%s(%s:%i): readProcStat failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("readProcStat failed"); goto fail; } if (ps.numThreads <= 1) { const char *const image = readProcExe(printb, pid, -1, b1); if (image == NULL) { - logg->logMessage("%s(%s:%i): readImage failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("readImage failed"); goto fail; } - buffer->comm(currTime, pid, pid, image, ps.comm); + buffer->marshalComm(currTime, pid, pid, image, ps.comm); } else { if (!readProcTask(currTime, buffer, pid, printb, b1, b2)) { - logg->logMessage("%s(%s:%i): readProcTask failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("readProcTask failed"); goto fail; } } @@ -213,7 +213,7 @@ bool readProcMaps(const uint64_t currTime, Buffer *const buffer, DynBuf *const p DIR *proc = opendir("/proc"); if (proc == NULL) { - logg->logMessage("%s(%s:%i): opendir failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("opendir failed"); return result; } @@ -227,16 +227,16 @@ bool readProcMaps(const uint64_t currTime, Buffer *const buffer, DynBuf *const p } if (!printb->printf("/proc/%i/maps", pid)) { - logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("DynBuf::printf failed"); goto fail; } if (!b->read(printb->getBuf())) { - logg->logMessage("%s(%s:%i): DynBuf::read failed, likely because the process exited", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("DynBuf::read failed, likely because the process exited"); // This is not a fatal error - the process just doesn't exist any more continue; } - buffer->maps(currTime, pid, pid, b->getBuf()); + buffer->marshalMaps(currTime, pid, pid, b->getBuf()); } result = true; @@ -251,7 +251,7 @@ bool readKallsyms(const uint64_t currTime, Buffer *const buffer, const bool *con int fd = ::open("/proc/kallsyms", O_RDONLY | O_CLOEXEC); if (fd < 0) { - logg->logMessage("%s(%s:%i): open failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("open failed"); return true; }; @@ -260,7 +260,7 @@ bool readKallsyms(const uint64_t currTime, Buffer *const buffer, const bool *con while (gSessionData->mSessionIsActive && !ACCESS_ONCE(*isDone)) { // Assert there is still space in the buffer if (sizeof(buf) - pos - 1 == 0) { - logg->logError(__FILE__, __LINE__, "no space left in buffer"); + logg->logError("no space left in buffer"); handleException(); } @@ -268,13 +268,13 @@ bool readKallsyms(const uint64_t currTime, Buffer *const buffer, const bool *con // -1 to reserve space for \0 const ssize_t bytes = ::read(fd, buf + pos, sizeof(buf) - pos - 1); if (bytes < 0) { - logg->logError(__FILE__, __LINE__, "read failed", __FUNCTION__, __FILE__, __LINE__); + logg->logError("read failed"); handleException(); } if (bytes == 0) { // Assert the buffer is empty if (pos != 0) { - logg->logError(__FILE__, __LINE__, "buffer not empty on eof"); + logg->logError("buffer not empty on eof"); handleException(); } break; @@ -288,13 +288,13 @@ bool readKallsyms(const uint64_t currTime, Buffer *const buffer, const bool *con if (buf[newline] == '\n') { const char was = buf[newline + 1]; buf[newline + 1] = '\0'; - buffer->kallsyms(currTime, buf); + buffer->marshalKallsyms(currTime, buf); // Sleep 3 ms to avoid sending out too much data too quickly usleep(3000); buf[0] = was; // Assert the memory regions do not overlap if (pos - newline >= newline + 1) { - logg->logError(__FILE__, __LINE__, "memcpy src and dst overlap"); + logg->logError("memcpy src and dst overlap"); handleException(); } if (pos - newline - 2 > 0) { diff --git a/tools/gator/daemon/Proc.h b/tools/gator/daemon/Proc.h index 2a1a7cbc1e99..fcc48c546d05 100644 --- a/tools/gator/daemon/Proc.h +++ b/tools/gator/daemon/Proc.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/Sender.cpp b/tools/gator/daemon/Sender.cpp index 8a54a6678974..d7ad757165a2 100644 --- a/tools/gator/daemon/Sender.cpp +++ b/tools/gator/daemon/Sender.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -30,7 +30,7 @@ Sender::Sender(OlySocket* socket) { // Streamline will send data prior to the magic sequence for legacy support, which should be ignored for v4+ while (strcmp("STREAMLINE", streamline) != 0) { if (mDataSocket->receiveString(streamline, sizeof(streamline)) == -1) { - logg->logError(__FILE__, __LINE__, "Socket disconnected"); + logg->logError("Socket disconnected"); handleException(); } } @@ -67,7 +67,7 @@ void Sender::createDataFile(char* apcDir) { sprintf(mDataFileName, "%s/0000000000", apcDir); mDataFile = fopen_cloexec(mDataFileName, "wb"); if (!mDataFile) { - logg->logError(__FILE__, __LINE__, "Failed to open binary file: %s", mDataFileName); + logg->logError("Failed to open binary file: %s", mDataFileName); handleException(); } } @@ -120,7 +120,7 @@ void Sender::writeData(const char* data, int length, int type) { logg->logMessage("Writing data with length %d", length); // Send data to the data file if (fwrite(data, 1, length, mDataFile) != (unsigned int)length) { - logg->logError(__FILE__, __LINE__, "Failed writing binary file %s", mDataFileName); + logg->logError("Failed writing binary file %s", mDataFileName); handleException(); } } diff --git a/tools/gator/daemon/Sender.h b/tools/gator/daemon/Sender.h index 5aa911713820..8f542026e90d 100644 --- a/tools/gator/daemon/Sender.h +++ b/tools/gator/daemon/Sender.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/SessionData.cpp b/tools/gator/daemon/SessionData.cpp index 0e65d7842647..2b661bdf294c 100644 --- a/tools/gator/daemon/SessionData.cpp +++ b/tools/gator/daemon/SessionData.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -13,7 +13,6 @@ #include #include -#include "CPUFreqDriver.h" #include "DiskIODriver.h" #include "FSDriver.h" #include "HwmonDriver.h" @@ -31,8 +30,7 @@ SessionData::SessionData() { usDrivers[1] = new FSDriver(); usDrivers[2] = new MemInfoDriver(); usDrivers[3] = new NetDriver(); - usDrivers[4] = new CPUFreqDriver(); - usDrivers[5] = new DiskIODriver(); + usDrivers[4] = new DiskIODriver(); initialize(); } @@ -50,7 +48,7 @@ void SessionData::initialize() { // Share mCpuIds across all instances of gatord mCpuIds = (int *)mmap(NULL, cpuIdSize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); if (mCpuIds == MAP_FAILED) { - logg->logError(__FILE__, __LINE__, "Unable to mmap shared memory for cpuids"); + logg->logError("Unable to mmap shared memory for cpuids"); handleException(); } memset(mCpuIds, -1, cpuIdSize); @@ -61,6 +59,7 @@ void SessionData::initialize() { mConfigurationXMLPath = NULL; mSessionXMLPath = NULL; mEventsXMLPath = NULL; + mEventsXMLAppend = NULL; mTargetPath = NULL; mAPCDir = NULL; mCaptureWorkingDir = NULL; @@ -75,6 +74,7 @@ void SessionData::initialize() { // sysconf(_SC_NPROCESSORS_CONF) is unreliable on 2.6 Android, get the value from the kernel module mCores = 1; mPageSize = 0; + mAnnotateStart = -1; } void SessionData::parseSessionXML(char* xmlString) { @@ -91,7 +91,7 @@ void SessionData::parseSessionXML(char* xmlString) { } else if (strcmp(session.parameters.sample_rate, "none") == 0) { mSampleRate = 0; } else { - logg->logError(__FILE__, __LINE__, "Invalid sample rate (%s) in session xml.", session.parameters.sample_rate); + logg->logError("Invalid sample rate (%s) in session xml.", session.parameters.sample_rate); handleException(); } mBacktraceDepth = session.parameters.call_stack_unwinding == true ? 128 : 0; @@ -108,7 +108,7 @@ void SessionData::parseSessionXML(char* xmlString) { } else if (strcmp(session.parameters.buffer_mode, "large") == 0) { mTotalBufferSize = 16; } else { - logg->logError(__FILE__, __LINE__, "Invalid value for buffer mode in session xml."); + logg->logError("Invalid value for buffer mode in session xml."); handleException(); } @@ -120,7 +120,7 @@ void SessionData::parseSessionXML(char* xmlString) { } if (!mAllowCommands && (mCaptureCommand != NULL)) { - logg->logError(__FILE__, __LINE__, "Running a command during a capture is not currently allowed. Please restart gatord with the -a flag."); + logg->logError("Running a command during a capture is not currently allowed. Please restart gatord with the -a flag."); handleException(); } } @@ -139,6 +139,20 @@ void SessionData::readModel() { fclose(fh); } +static void setImplementer(int &cpuId, const int implementer) { + if (cpuId == -1) { + cpuId = 0; + } + cpuId |= implementer << 12; +} + +static void setPart(int &cpuId, const int part) { + if (cpuId == -1) { + cpuId = 0; + } + cpuId |= part; +} + void SessionData::readCpuInfo() { char temp[256]; // arbitrarily large amount mMaxCpuId = -1; @@ -150,7 +164,7 @@ void SessionData::readCpuInfo() { return; } - bool foundCoreName = false; + bool foundCoreName = (strcmp(mCoreName, CORE_NAME_UNKNOWN) != 0); int processor = -1; while (fgets(temp, sizeof(temp), f)) { const size_t len = strlen(temp); @@ -166,10 +180,11 @@ void SessionData::readCpuInfo() { temp[len - 1] = '\0'; } - const bool foundHardware = strstr(temp, "Hardware") != 0; + const bool foundHardware = !foundCoreName && strstr(temp, "Hardware") != 0; + const bool foundCPUImplementer = strstr(temp, "CPU implementer") != 0; const bool foundCPUPart = strstr(temp, "CPU part") != 0; const bool foundProcessor = strstr(temp, "processor") != 0; - if (foundHardware || foundCPUPart || foundProcessor) { + if (foundHardware || foundCPUImplementer || foundCPUPart || foundProcessor) { char* position = strchr(temp, ':'); if (position == NULL || (unsigned int)(position - temp) + 2 >= strlen(temp)) { logg->logMessage("Unknown format of /proc/cpuinfo\n" @@ -178,22 +193,31 @@ void SessionData::readCpuInfo() { } position += 2; - if (foundHardware && (strcmp(mCoreName, CORE_NAME_UNKNOWN) == 0)) { + if (foundHardware) { strncpy(mCoreName, position, sizeof(mCoreName)); mCoreName[sizeof(mCoreName) - 1] = 0; // strncpy does not guarantee a null-terminated string foundCoreName = true; } + if (foundCPUImplementer) { + const int implementer = strtol(position, NULL, 0); + if (processor >= NR_CPUS) { + logg->logMessage("Too many processors, please increase NR_CPUS"); + } else if (processor >= 0) { + setImplementer(mCpuIds[processor], implementer); + } else { + setImplementer(mMaxCpuId, implementer); + } + } + if (foundCPUPart) { const int cpuId = strtol(position, NULL, 0); - // 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 - if (cpuId > mMaxCpuId) { - mMaxCpuId = cpuId; - } if (processor >= NR_CPUS) { logg->logMessage("Too many processors, please increase NR_CPUS"); } else if (processor >= 0) { - mCpuIds[processor] = cpuId; + setPart(mCpuIds[processor], cpuId); + } else { + setPart(mMaxCpuId, cpuId); } } @@ -203,6 +227,13 @@ void SessionData::readCpuInfo() { } } + // 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 + for (int i = 0; i < NR_CPUS; ++i) { + if (mCpuIds[i] > mMaxCpuId) { + mMaxCpuId = mCpuIds[i]; + } + } + if (!foundCoreName) { logg->logMessage("Could not determine core name from /proc/cpuinfo\n" "The core name in the captured xml file will be 'unknown'."); @@ -213,7 +244,7 @@ void SessionData::readCpuInfo() { uint64_t getTime() { struct timespec ts; if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts) != 0) { - logg->logError(__FILE__, __LINE__, "Failed to get uptime"); + logg->logError("Failed to get uptime"); handleException(); } return (NS_PER_S*ts.tv_sec + ts.tv_nsec); diff --git a/tools/gator/daemon/SessionData.h b/tools/gator/daemon/SessionData.h index ed282af4a869..d0c8900317a5 100644 --- a/tools/gator/daemon/SessionData.h +++ b/tools/gator/daemon/SessionData.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -11,7 +11,6 @@ #include -#include "AnnotateListener.h" #include "Config.h" #include "Counter.h" #include "FtraceDriver.h" @@ -19,7 +18,7 @@ #include "MaliVideoDriver.h" #include "PerfDriver.h" -#define PROTOCOL_VERSION 20 +#define PROTOCOL_VERSION 21 // Differentiates development versions (timestamp) from release versions #define PROTOCOL_DEV 1000 @@ -43,18 +42,18 @@ public: void readModel(); void readCpuInfo(); - PolledDriver *usDrivers[6]; + PolledDriver *usDrivers[5]; KMod kmod; PerfDriver perf; MaliVideoDriver maliVideo; FtraceDriver ftraceDriver; - AnnotateListener annotateListener; char mCoreName[MAX_STRING_LEN]; struct ImageLinkList *mImages; char *mConfigurationXMLPath; char *mSessionXMLPath; char *mEventsXMLPath; + char *mEventsXMLAppend; char *mTargetPath; char *mAPCDir; char *mCaptureWorkingDir; @@ -81,6 +80,7 @@ public: int mPageSize; int *mCpuIds; int mMaxCpuId; + int mAnnotateStart; // PMU Counters int mCounterOverflow; @@ -93,6 +93,7 @@ private: }; extern SessionData* gSessionData; +extern const char *const gSrcMd5; uint64_t getTime(); int getEventKey(); diff --git a/tools/gator/daemon/SessionXML.cpp b/tools/gator/daemon/SessionXML.cpp index dea4c8f299ec..c638dea45912 100644 --- a/tools/gator/daemon/SessionXML.cpp +++ b/tools/gator/daemon/SessionXML.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -36,7 +36,7 @@ SessionXML::SessionXML(const char *str) { parameters.call_stack_unwinding = false; parameters.live_rate = 0; mSessionXML = str; - logg->logMessage(mSessionXML); + logg->logMessage("%s", mSessionXML); } SessionXML::~SessionXML() { @@ -55,7 +55,7 @@ void SessionXML::parse() { return; } - logg->logError(__FILE__, __LINE__, "No session tag found in the session.xml file"); + logg->logError("No session tag found in the session.xml file"); handleException(); } @@ -63,7 +63,7 @@ void SessionXML::sessionTag(mxml_node_t *tree, mxml_node_t *node) { int version = 0; if (mxmlElementGetAttr(node, ATTR_VERSION)) version = strtol(mxmlElementGetAttr(node, ATTR_VERSION), NULL, 10); if (version != 1) { - logg->logError(__FILE__, __LINE__, "Invalid session.xml version: %d", version); + logg->logError("Invalid session.xml version: %d", version); handleException(); } diff --git a/tools/gator/daemon/SessionXML.h b/tools/gator/daemon/SessionXML.h index 53965749c74b..2ba276a38021 100644 --- a/tools/gator/daemon/SessionXML.h +++ b/tools/gator/daemon/SessionXML.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/Setup.cpp b/tools/gator/daemon/Setup.cpp index d4ce0328c633..7dd83ceafcce 100644 --- a/tools/gator/daemon/Setup.cpp +++ b/tools/gator/daemon/Setup.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2014. All rights reserved. + * Copyright (C) ARM Limited 2014-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -15,7 +15,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -24,12 +26,17 @@ #include "Config.h" #include "DynBuf.h" #include "Logging.h" +#include "SessionData.h" + +#define GATOR_MSG "gator: " +#define GATOR_ERROR "gator: error: " +#define GATOR_CONFIRM "gator: confirm: " bool getLinuxVersion(int version[3]) { // Check the kernel version struct utsname utsname; if (uname(&utsname) != 0) { - logg->logMessage("%s(%s:%i): uname failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("uname failed"); return false; } @@ -57,7 +64,7 @@ static int pgrep_gator(DynBuf *const printb) { DIR *proc = opendir("/proc"); if (proc == NULL) { - logg->logError(__FILE__, __LINE__, "gator: error: opendir failed"); + logg->logError(GATOR_ERROR "opendir failed"); handleException(); } @@ -73,7 +80,7 @@ static int pgrep_gator(DynBuf *const printb) { } if (!printb->printf("/proc/%i/stat", pid)) { - logg->logError(__FILE__, __LINE__, "gator: error: DynBuf::printf failed"); + logg->logError(GATOR_ERROR "DynBuf::printf failed"); handleException(); } @@ -84,21 +91,35 @@ static int pgrep_gator(DynBuf *const printb) { char *comm = strchr(b.getBuf(), '('); if (comm == NULL) { - logg->logError(__FILE__, __LINE__, "gator: error: parsing stat begin failed"); + logg->logError(GATOR_ERROR "parsing stat comm begin failed"); handleException(); } ++comm; char *const str = strrchr(comm, ')'); if (str == NULL) { - logg->logError(__FILE__, __LINE__, "gator: error: parsing stat end failed"); + logg->logError(GATOR_ERROR "parsing stat comm end failed"); handleException(); } *str = '\0'; - if (strncmp(comm, "gator", 5) == 0) { - // Assume there is only one gator process - return pid; + if (strncmp(comm, "gator", 5) != 0) { + continue; + } + + char state; + const int count = sscanf(str + 2, " %c ", &state); + if (count != 1) { + logg->logError(GATOR_ERROR "parsing stat state failed"); + handleException(); + } + + if (state == 'Z') { + // This gator is a zombie, ignore + continue; } + + // Assume there is only one gator process + return pid; } closedir(proc); @@ -106,73 +127,106 @@ static int pgrep_gator(DynBuf *const printb) { return -1; } -int update(const char *const gatorPath) { - printf("gator: starting\n"); +static bool confirm(const char *const message) { + char buf[1<<10]; + + printf(GATOR_CONFIRM "%s\n", message); + while (fgets(buf, sizeof(buf), stdin) != NULL) { + if (strcmp(buf, "y\n") == 0) { + return true; + } + if (strcmp(buf, "n\n") == 0) { + return false; + } + // Ignore unrecognized input + } + + return false; +} + +void update(const char *const gatorPath) { + printf(GATOR_MSG "starting\n"); int version[3]; if (!getLinuxVersion(version)) { - logg->logError(__FILE__, __LINE__, "gator: error: getLinuxVersion failed"); + logg->logError(GATOR_ERROR "getLinuxVersion failed"); handleException(); } if (KERNEL_VERSION(version[0], version[1], version[2]) < KERNEL_VERSION(2, 6, 32)) { - logg->logError(__FILE__, __LINE__, "gator: error: Streamline can't automatically setup gator as this kernel version is not supported. Please upgrade the kernel on your device."); + logg->logError(GATOR_ERROR "Streamline can't automatically setup gator as this kernel version is not supported. Please upgrade the kernel on your device."); handleException(); } if (KERNEL_VERSION(version[0], version[1], version[2]) < KERNEL_VERSION(3, 4, 0)) { - logg->logError(__FILE__, __LINE__, "gator: error: Streamline can't automatically setup gator as gator.ko is required for this version of Linux. Please build gator.ko and gatord and install them on your device."); - handleException(); - } - - if (access("/sys/module/gator", F_OK) == 0) { - logg->logError(__FILE__, __LINE__, "gator: error: Streamline has detected that the gator kernel module is loaded on your device. Please build an updated version of gator.ko and gatord and install them on your device."); + logg->logError(GATOR_ERROR "Streamline can't automatically setup gator as gator.ko is required for this version of Linux. Please build gator.ko and gatord and install them on your device."); handleException(); } if (geteuid() != 0) { - printf("gator: trying sudo\n"); + printf(GATOR_MSG "trying sudo\n"); execlp("sudo", "sudo", gatorPath, "-u", NULL); // Streamline will provide the password if needed - printf("gator: trying su\n"); + printf(GATOR_MSG "trying su\n"); char buf[1<<10]; - snprintf(buf, sizeof(buf), "%s -u", gatorPath); - execlp("su", "su", "-", "-c", buf, NULL); + /* + * Different versions of su handle additional -c command line options differently and expect the + * arguments in different ways. Try both ways wrapped in a shell. + * + * Then invoke another shell after su as it avoids odd failures on some Android systems + */ + snprintf(buf, sizeof(buf), "su -c \"sh -c '%s -u'\" || su -c sh -c '%s -u'", gatorPath, gatorPath); + execlp("sh", "sh", "-c", buf, NULL); // Streamline will provide the password if needed - logg->logError(__FILE__, __LINE__, "gator: error: Streamline was unable to sudo to root on your device. Please double check passwords, ensure sudo or su work with this user or try a different username."); + logg->logError(GATOR_ERROR "Streamline was unable to sudo to root on your device. Please double check passwords, ensure sudo or su work with this user or try a different username."); handleException(); } - printf("gator: now root\n"); + printf(GATOR_MSG "now root\n"); + + if (access("/sys/module/gator", F_OK) == 0) { + if (!confirm("Streamline has detected that the gator kernel module is loaded on your device. Click yes to switch to user space gator, click no to abort the install.")) { + printf("gator: cancel\n"); + exit(-1); + } + } // setenforce 0 not needed for userspace gator // Kill existing gator - DynBuf gatorStatPath; - int gator_main = pgrep_gator(&gatorStatPath); + DynBuf printb; + int gator_main = pgrep_gator(&printb); if (gator_main > 0) { if (kill(gator_main, SIGTERM) != 0) { - logg->logError(__FILE__, __LINE__, "gator: error: kill SIGTERM failed"); + logg->logError(GATOR_ERROR "kill SIGTERM failed"); + handleException(); + } + if (!printb.printf("/proc/%i/exe", gator_main)) { + logg->logError(GATOR_ERROR "DynBuf::printf failed"); handleException(); } for (int i = 0; ; ++i) { - if (access(gatorStatPath.getBuf(), F_OK) != 0) { + // /proc//exe exists but will not be accessible for zombies + if (access(printb.getBuf(), F_OK) != 0) { break; } if (i == 5) { if (kill(gator_main, SIGKILL) != 0) { - logg->logError(__FILE__, __LINE__, "gator: error: kill SIGKILL failed"); + logg->logError(GATOR_ERROR "kill SIGKILL failed"); handleException(); } } else if (i >= 10) { - logg->logError(__FILE__, __LINE__, "gator: error: unable to kill running gator"); + logg->logError(GATOR_ERROR "unable to kill running gator"); handleException(); } sleep(1); } } - printf("gator: no gatord running\n"); + printf(GATOR_MSG "no gatord running\n"); + + umount("/dev/gator"); + syscall(__NR_delete_module, "gator", O_NONBLOCK); rename("gatord", "gatord.old"); rename("gator.ko", "gator.ko.old"); @@ -183,50 +237,88 @@ int update(const char *const gatorPath) { if (dot != NULL) { *dot = '\0'; if (rename(gatorPath, newGatorPath) != 0) { - logg->logError(__FILE__, __LINE__, "gator: error: rename failed"); + logg->logError(GATOR_ERROR "rename failed"); handleException(); } } - // Fork and start gatord (redirect stdout and stderr) + char buf[128]; + int pipefd[2]; + if (pipe_cloexec(pipefd) != 0) { + logg->logError(GATOR_ERROR "pipe failed"); + handleException(); + } + + // Fork and start gatord (redirect stdin, stdout and stderr so shell can close) int child = fork(); if (child < 0) { - logg->logError(__FILE__, __LINE__, "gator: error: fork failed"); + logg->logError(GATOR_ERROR "fork failed"); handleException(); } else if (child == 0) { - int inFd = open("/dev/null", O_RDONLY | O_CLOEXEC); + int inFd; + int outFd; + int errFd; + int result = -1; + + buf[0] = '\0'; + close(pipefd[0]); + + inFd = open("/dev/null", O_RDONLY | O_CLOEXEC); if (inFd < 0) { - logg->logError(__FILE__, __LINE__, "gator: error: open of /dev/null failed"); - handleException(); + snprintf(buf, sizeof(buf), GATOR_ERROR "open of /dev/null failed"); + goto fail_exit; } - int outFd = open("gatord.out", O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0600); + outFd = open("gatord.out", O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644); if (outFd < 0) { - logg->logError(__FILE__, __LINE__, "gator: error: open of gatord.out failed"); - handleException(); + snprintf(buf, sizeof(buf), GATOR_ERROR "open of gatord.out failed"); + goto fail_exit; } - int errFd = open("gatord.err", O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0600); + errFd = open("gatord.err", O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644); if (errFd < 0) { - logg->logError(__FILE__, __LINE__, "gator: error: open of gatord.err failed"); - handleException(); + snprintf(buf, sizeof(buf), GATOR_ERROR "open of gatord.err failed"); + goto fail_exit; } if (dup2(inFd, STDIN_FILENO) < 0) { - logg->logError(__FILE__, __LINE__, "gator: error: dup2 for stdin failed"); - handleException(); + snprintf(buf, sizeof(buf), GATOR_ERROR "dup2 for stdin failed"); + goto fail_exit; } + fflush(stdout); if (dup2(outFd, STDOUT_FILENO) < 0) { - logg->logError(__FILE__, __LINE__, "gator: error: dup2 for stdout failed"); - handleException(); + snprintf(buf, sizeof(buf), GATOR_ERROR "dup2 for stdout failed"); + goto fail_exit; } + fflush(stderr); if (dup2(errFd, STDERR_FILENO) < 0) { - logg->logError(__FILE__, __LINE__, "gator: error: dup2 for stderr failed"); - handleException(); + snprintf(buf, sizeof(buf), GATOR_ERROR "dup2 for stderr failed"); + goto fail_exit; } - execlp(newGatorPath, newGatorPath, "-a", NULL); - logg->logError(__FILE__, __LINE__, "gator: error: execlp failed"); - handleException(); + + snprintf(buf, sizeof(buf), GATOR_MSG "done"); + result = 0; + + fail_exit: + if (buf[0] != '\0') { + const ssize_t bytes = write(pipefd[1], buf, sizeof(buf)); + // Can't do anything if this fails + (void)bytes; + } + close(pipefd[1]); + + if (result == 0) { + // Continue to execute gator normally + return; + } + exit(-1); } - printf("gator: done\n"); + close(pipefd[1]); + const ssize_t bytes = read(pipefd[0], buf, sizeof(buf)); + if (bytes > 0) { + logg->logError("%s", buf); + handleException(); + } + close(pipefd[0]); - return 0; + // Exit so parent shell can move on + exit(0); } diff --git a/tools/gator/daemon/Setup.h b/tools/gator/daemon/Setup.h index 280d61139784..427e71788c36 100644 --- a/tools/gator/daemon/Setup.h +++ b/tools/gator/daemon/Setup.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2014. All rights reserved. + * Copyright (C) ARM Limited 2014-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -13,6 +13,6 @@ #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) bool getLinuxVersion(int version[3]); -int update(const char *const gatorPath); +void update(const char *const gatorPath); #endif // SETUP_H diff --git a/tools/gator/daemon/Source.cpp b/tools/gator/daemon/Source.cpp index 60cf704e599b..64d6206895b0 100644 --- a/tools/gator/daemon/Source.cpp +++ b/tools/gator/daemon/Source.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -18,7 +18,7 @@ Source::~Source() { void Source::start() { if (pthread_create(&mThreadID, NULL, runStatic, this)) { - logg->logError(__FILE__, __LINE__, "Failed to create source thread"); + logg->logError("Failed to create source thread"); handleException(); } } diff --git a/tools/gator/daemon/Source.h b/tools/gator/daemon/Source.h index 56ac3d6e94f3..b9369be5198b 100644 --- a/tools/gator/daemon/Source.h +++ b/tools/gator/daemon/Source.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/StreamlineSetup.cpp b/tools/gator/daemon/StreamlineSetup.cpp index 2b61eaeb290d..e37f2712cd04 100644 --- a/tools/gator/daemon/StreamlineSetup.cpp +++ b/tools/gator/daemon/StreamlineSetup.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2011-2014. All rights reserved. + * Copyright (C) ARM Limited 2011-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -68,7 +68,7 @@ StreamlineSetup::StreamlineSetup(OlySocket* s) { sendData(NULL, 0, RESPONSE_ACK); break; default: - logg->logError(__FILE__, __LINE__, "Target error: Unknown command type, %d", type); + logg->logError("Target error: Unknown command type, %d", type); handleException(); } @@ -76,7 +76,7 @@ StreamlineSetup::StreamlineSetup(OlySocket* s) { } if (gSessionData->mCounterOverflow > 0) { - logg->logError(__FILE__, __LINE__, "Only %i performance counters are permitted, %i are selected", MAX_PERFORMANCE_COUNTERS, gSessionData->mCounterOverflow); + logg->logError("Only %i performance counters are permitted, %i are selected", MAX_PERFORMANCE_COUNTERS, gSessionData->mCounterOverflow); handleException(); } } @@ -96,7 +96,7 @@ char* StreamlineSetup::readCommand(int* command) { gSessionData->mWaitingOnCommand = false; if (response < 0) { - logg->logError(__FILE__, __LINE__, "Target error: Unexpected socket disconnect"); + logg->logError("Target error: Unexpected socket disconnect"); handleException(); } @@ -105,21 +105,21 @@ char* StreamlineSetup::readCommand(int* command) { // add artificial limit if ((length < 0) || length > 1024 * 1024) { - logg->logError(__FILE__, __LINE__, "Target error: Invalid length received, %d", length); + logg->logError("Target error: Invalid length received, %d", length); handleException(); } // allocate memory to contain the xml file, size of zero returns a zero size object data = (char*)calloc(length + 1, 1); if (data == NULL) { - logg->logError(__FILE__, __LINE__, "Unable to allocate memory for xml"); + logg->logError("Unable to allocate memory for xml"); handleException(); } // receive data response = mSocket->receiveNBytes(data, length); if (response < 0) { - logg->logError(__FILE__, __LINE__, "Target error: Unexpected socket disconnect"); + logg->logError("Target error: Unexpected socket disconnect"); handleException(); } @@ -222,7 +222,7 @@ void StreamlineSetup::sendDefaults() { // Artificial size restriction if (size > 1024*1024) { - logg->logError(__FILE__, __LINE__, "Corrupt default configuration file"); + logg->logError("Corrupt default configuration file"); handleException(); } @@ -241,7 +241,7 @@ void StreamlineSetup::sendCounters() { } if (count == 0) { - 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"); + logg->logError("No counters found, this could be because /dev/gator/events can not be read or because perf is not working correctly"); handleException(); } @@ -258,7 +258,7 @@ void StreamlineSetup::writeConfiguration(char* xml) { ConfigurationXML::getPath(path); if (util->writeToDisk(path, xml) < 0) { - logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify write permissions to this path.", path); + logg->logError("Error writing %s\nPlease verify write permissions to this path.", path); handleException(); } @@ -266,7 +266,7 @@ void StreamlineSetup::writeConfiguration(char* xml) { { ConfigurationXML configuration; } if (gSessionData->mCounterOverflow > 0) { - logg->logError(__FILE__, __LINE__, "Only %i performance counters are permitted, %i are selected", MAX_PERFORMANCE_COUNTERS, gSessionData->mCounterOverflow); + logg->logError("Only %i performance counters are permitted, %i are selected", MAX_PERFORMANCE_COUNTERS, gSessionData->mCounterOverflow); handleException(); } } diff --git a/tools/gator/daemon/StreamlineSetup.h b/tools/gator/daemon/StreamlineSetup.h index 623e14f2b64a..d8b162606436 100644 --- a/tools/gator/daemon/StreamlineSetup.h +++ b/tools/gator/daemon/StreamlineSetup.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/UEvent.cpp b/tools/gator/daemon/UEvent.cpp index f94a995393e8..6a69f5ab137e 100644 --- a/tools/gator/daemon/UEvent.cpp +++ b/tools/gator/daemon/UEvent.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -34,7 +34,7 @@ UEvent::~UEvent() { bool UEvent::init() { mFd = socket_cloexec(PF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT); if (mFd < 0) { - logg->logMessage("%s(%s:%i): socket failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("socket failed"); return false; } @@ -44,7 +44,7 @@ bool UEvent::init() { sockaddr.nl_groups = 1; // bitmask: (1 << 0) == kernel events, (1 << 1) == udev events sockaddr.nl_pid = 0; if (bind(mFd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) != 0) { - logg->logMessage("%s(%s:%i): bind failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("bind failed"); return false; } @@ -54,7 +54,7 @@ bool UEvent::init() { bool UEvent::read(UEventResult *const result) { ssize_t bytes = recv(mFd, result->mBuf, sizeof(result->mBuf), 0); if (bytes <= 0) { - logg->logMessage("%s(%s:%i): recv failed", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("recv failed"); return false; } @@ -64,6 +64,7 @@ bool UEvent::read(UEventResult *const result) { for (int pos = 0; pos < bytes; pos += strlen(result->mBuf + pos) + 1) { char *const str = result->mBuf + pos; + logg->logMessage("uevent + %i: %s", pos, str); if (strncmp(str, ACTION, sizeof(ACTION) - 1) == 0) { result->mAction = str + sizeof(ACTION) - 1; } else if (strncmp(str, DEVPATH, sizeof(DEVPATH) - 1) == 0) { diff --git a/tools/gator/daemon/UEvent.h b/tools/gator/daemon/UEvent.h index 2f7ef2c93f5d..4c00f6cff112 100644 --- a/tools/gator/daemon/UEvent.h +++ b/tools/gator/daemon/UEvent.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2013-2014. All rights reserved. + * Copyright (C) ARM Limited 2013-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/UserSpaceSource.cpp b/tools/gator/daemon/UserSpaceSource.cpp index 4a9b22f4b555..f58f828e6e2e 100644 --- a/tools/gator/daemon/UserSpaceSource.cpp +++ b/tools/gator/daemon/UserSpaceSource.cpp @@ -1,13 +1,16 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#define __STDC_FORMAT_MACROS + #include "UserSpaceSource.h" +#include #include #include @@ -35,45 +38,45 @@ void UserSpaceSource::run() { gSessionData->usDrivers[i]->start(); } - int64_t monotonic_started = 0; - while (monotonic_started <= 0) { + int64_t monotonicStarted = 0; + while (monotonicStarted <= 0 && gSessionData->mSessionIsActive) { usleep(10); if (gSessionData->perf.isSetup()) { - monotonic_started = gSessionData->mMonotonicStarted; + monotonicStarted = gSessionData->mMonotonicStarted; } else { - if (DriverSource::readInt64Driver("/dev/gator/started", &monotonic_started) == -1) { - logg->logError(__FILE__, __LINE__, "Error reading gator driver start time"); + if (DriverSource::readInt64Driver("/dev/gator/started", &monotonicStarted) == -1) { + logg->logError("Error reading gator driver start time"); handleException(); } - gSessionData->mMonotonicStarted = monotonic_started; + gSessionData->mMonotonicStarted = monotonicStarted; } } - uint64_t next_time = 0; + uint64_t nextTime = 0; while (gSessionData->mSessionIsActive) { - const uint64_t curr_time = getTime() - monotonic_started; + const uint64_t currTime = getTime() - monotonicStarted; // Sample ten times a second ignoring gSessionData->mSampleRate - next_time += NS_PER_S/10;//gSessionData->mSampleRate; - if (next_time < curr_time) { - logg->logMessage("Too slow, curr_time: %lli next_time: %lli", curr_time, next_time); - next_time = curr_time; + nextTime += NS_PER_S/10;//gSessionData->mSampleRate; + if (nextTime < currTime) { + logg->logMessage("Too slow, currTime: %" PRIi64 " nextTime: %" PRIi64, currTime, nextTime); + nextTime = currTime; } - if (mBuffer.eventHeader(curr_time)) { + if (mBuffer.eventHeader(currTime)) { for (int i = 0; i < ARRAY_LENGTH(gSessionData->usDrivers); ++i) { gSessionData->usDrivers[i]->read(&mBuffer); } // Only check after writing all counters so that time and corresponding counters appear in the same frame - mBuffer.check(curr_time); + mBuffer.check(currTime); } - if (mBuffer.bytesAvailable() <= 0) { + if (gSessionData->mOneShot && gSessionData->mSessionIsActive && (mBuffer.bytesAvailable() <= 0)) { logg->logMessage("One shot (counters)"); child->endSession(); } - usleep((next_time - curr_time)/NS_PER_US); + usleep((nextTime - currTime)/NS_PER_US); } mBuffer.setDone(); diff --git a/tools/gator/daemon/UserSpaceSource.h b/tools/gator/daemon/UserSpaceSource.h index 9b3666016dc5..0038dcb4c3d5 100644 --- a/tools/gator/daemon/UserSpaceSource.h +++ b/tools/gator/daemon/UserSpaceSource.h @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/c++.cpp b/tools/gator/daemon/c++.cpp index 6041e5e96469..caf6f1efdcde 100644 --- a/tools/gator/daemon/c++.cpp +++ b/tools/gator/daemon/c++.cpp @@ -1,7 +1,7 @@ /** * Minimal set of C++ functions so that libstdc++ is not required * - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/common.mk b/tools/gator/daemon/common.mk index 769a92e51a35..0d5a0a835d2c 100644 --- a/tools/gator/daemon/common.mk +++ b/tools/gator/daemon/common.mk @@ -6,7 +6,7 @@ # -std=c++0x is the planned new c++ standard # -std=c++98 is the 1998 c++ standard CPPFLAGS += -O3 -Wall -fno-exceptions -pthread -MMD -DETCDIR=\"/etc\" -Ilibsensors -CXXFLAGS += -fno-rtti -Wextra # -Weffc++ +CXXFLAGS += -fno-rtti -Wextra -Wshadow # -Weffc++ ifeq ($(WERROR),1) CPPFLAGS += -Werror endif @@ -41,7 +41,10 @@ libsensors/conf-parse.c: ; %.o: %.cpp $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $< -$(TARGET): $(CXX_SRC:%.cpp=%.o) $(C_SRC:%.c=%.o) +SrcMd5.cpp: $(wildcard *.cpp *.h mxml/*.c mxml/*.h libsensors/*.c libsensors/*.h) + echo 'extern const char *const gSrcMd5 = "'`ls $^ | grep -Ev '^(.*_xml\.h|$@)$$' | LC_ALL=C sort | xargs cat | md5sum | cut -b 1-32`'";' > $@ + +$(TARGET): $(CXX_SRC:%.cpp=%.o) $(C_SRC:%.c=%.o) SrcMd5.o $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ # Intentionally ignore CC as a native binary is required @@ -49,4 +52,4 @@ escape: escape.c gcc $^ -o $@ clean: - rm -f *.d *.o mxml/*.d mxml/*.o libsensors/*.d libsensors/*.o $(TARGET) escape events.xml events_xml.h defaults_xml.h + rm -f *.d *.o mxml/*.d mxml/*.o libsensors/*.d libsensors/*.o $(TARGET) escape events.xml events_xml.h defaults_xml.h SrcMd5.cpp diff --git a/tools/gator/daemon/defaults.xml b/tools/gator/daemon/defaults.xml index 086eca1e804e..31b127cdcfc6 100644 --- a/tools/gator/daemon/defaults.xml +++ b/tools/gator/daemon/defaults.xml @@ -44,6 +44,11 @@ + + + + + @@ -64,21 +69,5 @@ - - - - - - - - - - - - - - - - diff --git a/tools/gator/daemon/escape.c b/tools/gator/daemon/escape.c index 2b0863aaf425..99f434848cb3 100644 --- a/tools/gator/daemon/escape.c +++ b/tools/gator/daemon/escape.c @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/tools/gator/daemon/events-ARM11.xml b/tools/gator/daemon/events-ARM11.xml index 57e323546314..e481267b21ae 100644 --- a/tools/gator/daemon/events-ARM11.xml +++ b/tools/gator/daemon/events-ARM11.xml @@ -16,7 +16,7 @@ - + diff --git a/tools/gator/daemon/events-CCI-400.xml b/tools/gator/daemon/events-CCI-400.xml index 20002efd1543..40d91e582c19 100644 --- a/tools/gator/daemon/events-CCI-400.xml +++ b/tools/gator/daemon/events-CCI-400.xml @@ -1,5 +1,5 @@ - + - + \ No newline at end of file diff --git a/tools/gator/daemon/events-Mali-T62x_hw.xml b/tools/gator/daemon/events-Mali-T62x_hw.xml index 6ecc53c2ada1..4bc93068f75b 100644 --- a/tools/gator/daemon/events-Mali-T62x_hw.xml +++ b/tools/gator/daemon/events-Mali-T62x_hw.xml @@ -7,12 +7,13 @@ - - - - - - + + + + + + + @@ -78,32 +79,38 @@ - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - - + + + - + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/gator/daemon/events-Mali-T72x_hw.xml b/tools/gator/daemon/events-Mali-T72x_hw.xml index 5587534770c8..fd9cb0f16c6e 100644 --- a/tools/gator/daemon/events-Mali-T72x_hw.xml +++ b/tools/gator/daemon/events-Mali-T72x_hw.xml @@ -7,12 +7,13 @@ - - - - - - + + + + + + + @@ -67,29 +68,34 @@ - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + + diff --git a/tools/gator/daemon/events-Mali-T76x_hw.xml b/tools/gator/daemon/events-Mali-T76x_hw.xml index be74c5a42624..94d059fc09dd 100644 --- a/tools/gator/daemon/events-Mali-T76x_hw.xml +++ b/tools/gator/daemon/events-Mali-T76x_hw.xml @@ -7,12 +7,13 @@ - - - - - - + + + + + + + @@ -78,31 +79,39 @@ - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/gator/daemon/events-Mali-T82x_hw.xml b/tools/gator/daemon/events-Mali-T82x_hw.xml new file mode 100644 index 000000000000..5caa464a3078 --- /dev/null +++ b/tools/gator/daemon/events-Mali-T82x_hw.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/gator/daemon/events-Mali-T83x_hw.xml b/tools/gator/daemon/events-Mali-T83x_hw.xml new file mode 100644 index 000000000000..39f7acf31798 --- /dev/null +++ b/tools/gator/daemon/events-Mali-T83x_hw.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/gator/daemon/events-Mali-T86x_hw.xml b/tools/gator/daemon/events-Mali-T86x_hw.xml new file mode 100644 index 000000000000..6653543d5caa --- /dev/null +++ b/tools/gator/daemon/events-Mali-T86x_hw.xml @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/gator/daemon/events-Mali-T88x_hw.xml b/tools/gator/daemon/events-Mali-T88x_hw.xml new file mode 100644 index 000000000000..19385d19c9de --- /dev/null +++ b/tools/gator/daemon/events-Mali-T88x_hw.xml @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/gator/daemon/events-Other.xml b/tools/gator/daemon/events-Other.xml new file mode 100644 index 000000000000..8aec282b7e11 --- /dev/null +++ b/tools/gator/daemon/events-Other.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/gator/daemon/events-ftrace.xml b/tools/gator/daemon/events-ftrace.xml index 33ab7aab2196..ae5529f2678d 100644 --- a/tools/gator/daemon/events-ftrace.xml +++ b/tools/gator/daemon/events-ftrace.xml @@ -1,7 +1,22 @@ - - + + + + + + + + + + + + diff --git a/tools/gator/daemon/main.cpp b/tools/gator/daemon/main.cpp index fbce1e15d0d0..c68a892e74fc 100644 --- a/tools/gator/daemon/main.cpp +++ b/tools/gator/daemon/main.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) ARM Limited 2010-2014. All rights reserved. + * Copyright (C) ARM Limited 2010-2015. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -19,6 +19,7 @@ #include #include +#include "AnnotateListener.h" #include "CCNDriver.h" #include "Child.h" #include "EventsXML.h" @@ -133,7 +134,7 @@ public: memset(&mDstAns, 0, sizeof(mDstAns)); memcpy(mDstAns.rviHeader, "STR_ANS ", sizeof(mDstAns.rviHeader)); if (gethostname(mDstAns.dhcpName, sizeof(mDstAns.dhcpName) - 1) != 0) { - logg->logError(__FILE__, __LINE__, "gethostname failed"); + logg->logError("gethostname failed"); handleException(); } // Subvert the defaultGateway field for the port number @@ -156,7 +157,7 @@ public: addrlen = sizeof(sockaddr); read = recvfrom(mReq, &buf, sizeof(buf), 0, (struct sockaddr *)&sockaddr, &addrlen); if (read < 0) { - logg->logError(__FILE__, __LINE__, "recvfrom failed"); + logg->logError("recvfrom failed"); handleException(); } else if ((read == 12) && (memcmp(buf, DST_REQ, sizeof(DST_REQ)) == 0)) { // Don't care if sendto fails - gatord shouldn't exit because of it and Streamline will retry @@ -180,23 +181,29 @@ private: family = AF_INET; s = socket_cloexec(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (s == -1) { - logg->logError(__FILE__, __LINE__, "socket failed"); + logg->logError("socket failed"); handleException(); } } on = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)) != 0) { - logg->logError(__FILE__, __LINE__, "setsockopt failed"); + logg->logError("setsockopt REUSEADDR failed"); handleException(); } + // Listen on both IPv4 and IPv6 + on = 0; + if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&on, sizeof(on)) != 0) { + logg->logMessage("setsockopt IPV6_V6ONLY failed"); + } + memset((void*)&sockaddr, 0, sizeof(sockaddr)); sockaddr.sin6_family = family; sockaddr.sin6_port = htons(port); sockaddr.sin6_addr = in6addr_any; if (bind(s, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) { - logg->logError(__FILE__, __LINE__, "socket failed"); + logg->logError("socket failed"); handleException(); } @@ -252,7 +259,7 @@ static bool setupFilesystem(char* module) { // if still mounted if (access("/dev/gator/buffer", F_OK) == 0) { - 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"); + logg->logError("Unable to remove the running gator.ko. Manually remove the module or use the running module by not specifying one on the commandline"); handleException(); } } @@ -284,7 +291,7 @@ static bool setupFilesystem(char* module) { return false; } else { // gator location specified on the command line but it was not found - logg->logError(__FILE__, __LINE__, "gator module not found at %s", location); + logg->logError("gator module not found at %s", location); handleException(); } } @@ -296,13 +303,13 @@ static bool setupFilesystem(char* module) { snprintf(command, sizeof(command), "insmod %s >/dev/null 2>&1", location); if (system(command) != 0) { logg->logMessage("Unable to load gator.ko driver with command: %s", command); - 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"); + logg->logError("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"); handleException(); } } if (mountGatorFS() == -1) { - logg->logError(__FILE__, __LINE__, "Unable to mount the gator filesystem needed for profiling."); + logg->logError("Unable to mount the gator filesystem needed for profiling."); handleException(); } } @@ -326,7 +333,7 @@ static int shutdownFilesystem() { return 0; // success } -static const char OPTSTRING[] = "hvudap:s:c:e:m:o:"; +static const char OPTSTRING[] = "hvVudap:s:c:e:E:m:o:"; static bool hasDebugFlag(int argc, char** argv) { int c; @@ -368,11 +375,18 @@ static struct cmdline_t parseCommandLine(int argc, char** argv) { case 'e': gSessionData->mEventsXMLPath = optarg; break; + case 'E': + gSessionData->mEventsXMLAppend = optarg; + break; case 'm': cmdline.module = optarg; break; case 'p': cmdline.port = strtol(optarg, NULL, 10); + if ((cmdline.port == 8082) || (cmdline.port == 8083)) { + logg->logError("Gator can't use port %i, as it already uses ports 8082 and 8083 for annotations. Please select a different port.", cmdline.port); + handleException(); + } break; case 's': gSessionData->mSessionXMLPath = optarg; @@ -388,10 +402,11 @@ static struct cmdline_t parseCommandLine(int argc, char** argv) { break; case 'h': case '?': - logg->logError(__FILE__, __LINE__, + logg->logError( "%s. All parameters are optional:\n" - "-c config_xml path and filename of the configuration.xml to use\n" - "-e events_xml path and filename of the events.xml to use\n" + "-c config_xml path and filename of the configuration XML to use\n" + "-e events_xml path and filename of the events XML to use\n" + "-E events_xml path and filename of events XML to append\n" "-h this help page\n" "-m module path and filename of gator.ko\n" "-p port_number port upon which the server listens; default is 8080\n" @@ -399,12 +414,16 @@ static struct cmdline_t parseCommandLine(int argc, char** argv) { "-o apc_dir path and name of the output for a local capture\n" "-v version information\n" "-d enable debug messages\n" - "-a allow the user user to provide a command to run at the start of a capture" + "-a allow the user to issue a command from Streamline" , version_string); handleException(); break; case 'v': - logg->logError(__FILE__, __LINE__, version_string); + logg->logError("%s", version_string); + handleException(); + break; + case 'V': + logg->logError("%s\nSRC_MD5: %s", version_string, gSrcMd5); handleException(); break; } @@ -412,35 +431,38 @@ static struct cmdline_t parseCommandLine(int argc, char** argv) { // Error checking if (cmdline.port != DEFAULT_PORT && gSessionData->mSessionXMLPath != NULL) { - logg->logError(__FILE__, __LINE__, "Only a port or a session xml can be specified, not both"); + logg->logError("Only a port or a session xml can be specified, not both"); handleException(); } if (gSessionData->mTargetPath != NULL && gSessionData->mSessionXMLPath == NULL) { - logg->logError(__FILE__, __LINE__, "Missing -s command line option required for a local capture."); + logg->logError("Missing -s command line option required for a local capture."); handleException(); } if (optind < argc) { - logg->logError(__FILE__, __LINE__, "Unknown argument: %s. Use '-h' for help.", argv[optind]); + logg->logError("Unknown argument: %s. Use '-h' for help.", argv[optind]); handleException(); } return cmdline; } +static AnnotateListener annotateListener; + static void handleClient() { OlySocket client(sock->acceptConnection()); int pid = fork(); if (pid < 0) { // Error - logg->logError(__FILE__, __LINE__, "Fork process failed. Please power cycle the target device if this error persists."); + logg->logError("Fork process failed. Please power cycle the target device if this error persists."); } else if (pid == 0) { // Child sock->closeServerSocket(); udpListener.close(); monitor.close(); + annotateListener.close(); child = new Child(&client, numSessions + 1); child->run(); delete child; @@ -500,21 +522,23 @@ int main(int argc, char** argv) { struct cmdline_t cmdline = parseCommandLine(argc, argv); if (cmdline.update) { - return update(argv[0]); + update(argv[0]); + cmdline.update = false; + gSessionData->mAllowCommands = true; } // Verify root permissions uid_t euid = geteuid(); if (euid) { - logg->logError(__FILE__, __LINE__, "gatord must be launched with root privileges"); + logg->logError("gatord must be launched with root privileges"); handleException(); } // Call before setting up the SIGCHLD handler, as system() spawns child processes if (!setupFilesystem(cmdline.module)) { - logg->logMessage("Unable to setup gatorfs, trying perf"); + logg->logMessage("Unable to set up gatorfs, trying perf"); if (!gSessionData->perf.setup()) { - logg->logError(__FILE__, __LINE__, + logg->logError( "Unable to locate gator.ko driver:\n" " >>> gator.ko should be co-located with gatord in the same directory\n" " >>> OR insmod gator.ko prior to launching gatord\n" @@ -547,15 +571,23 @@ int main(int argc, char** argv) { child->run(); delete child; } else { - gSessionData->annotateListener.setup(); + annotateListener.setup(); + int pipefd[2]; + if (pipe_cloexec(pipefd) != 0) { + logg->logError("Unable to set up annotate pipe"); + handleException(); + } + gSessionData->mAnnotateStart = pipefd[1]; sock = new OlyServerSocket(cmdline.port); udpListener.setup(cmdline.port); if (!monitor.init() || !monitor.add(sock->getFd()) || !monitor.add(udpListener.getReq()) || - !monitor.add(gSessionData->annotateListener.getFd()) || + !monitor.add(annotateListener.getSockFd()) || + !monitor.add(annotateListener.getUdsFd()) || + !monitor.add(pipefd[0]) || false) { - logg->logError(__FILE__, __LINE__, "Monitor setup failed"); + logg->logError("Monitor setup failed"); handleException(); } // Forever loop, can be exited via a signal or exception @@ -564,7 +596,7 @@ int main(int argc, char** argv) { logg->logMessage("Waiting on connection..."); int ready = monitor.wait(events, ARRAY_LENGTH(events), -1); if (ready < 0) { - logg->logError(__FILE__, __LINE__, "Monitor::wait failed"); + logg->logError("Monitor::wait failed"); handleException(); } for (int i = 0; i < ready; ++i) { @@ -572,8 +604,16 @@ int main(int argc, char** argv) { handleClient(); } else if (events[i].data.fd == udpListener.getReq()) { udpListener.handle(); - } else if (events[i].data.fd == gSessionData->annotateListener.getFd()) { - gSessionData->annotateListener.handle(); + } else if (events[i].data.fd == annotateListener.getSockFd()) { + annotateListener.handleSock(); + } else if (events[i].data.fd == annotateListener.getUdsFd()) { + annotateListener.handleUds(); + } else if (events[i].data.fd == pipefd[0]) { + uint64_t val; + if (read(pipefd[0], &val, sizeof(val)) != sizeof(val)) { + logg->logMessage("Reading annotate pipe failed"); + } + annotateListener.signal(); } } }