mirror of
				https://github.com/HappyTanuki/BumbleCee.git
				synced 2025-10-25 17:35:58 +00:00 
			
		
		
		
	아마도? 쉘 인젝션 취약점 픽스
This commit is contained in:
		
							
								
								
									
										4
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							| @@ -102,6 +102,8 @@ | ||||
|         "hash_set": "cpp", | ||||
|         "regex": "cpp", | ||||
|         "stack": "cpp", | ||||
|         "__memory": "cpp" | ||||
|         "__memory": "cpp", | ||||
|         "__verbose_abort": "cpp", | ||||
|         "print": "cpp" | ||||
|     } | ||||
| } | ||||
| @@ -1,5 +1,7 @@ | ||||
| cmake_minimum_required (VERSION 3.6) | ||||
|  | ||||
| INCLUDE_DIRECTORIES(include . ${Boost_INCLUDE_DIR}) | ||||
|  | ||||
| list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) | ||||
| set(BOT_NAME "BumbleCee") | ||||
|  | ||||
| @@ -18,8 +20,11 @@ set(CMAKE_CXX_STANDARD 20) | ||||
| set(CMAKE_CXX_STANDARD_REQUIRED ON) | ||||
|  | ||||
| set(THREADS_PREFER_PTHREAD_FLAG TRUE) | ||||
| add_definitions( -DBOOST_ALL_NO_LIB ) | ||||
| set( Boost_USE_STATIC_LIBS ON ) | ||||
| find_package(Threads REQUIRED) | ||||
| find_package(OpenSSL REQUIRED) | ||||
| find_package(Boost REQUIRED) | ||||
|  | ||||
| target_include_directories(${BOT_NAME} PUBLIC | ||||
|     ${CMAKE_CURRENT_SOURCE_DIR}/include | ||||
| @@ -35,6 +40,7 @@ target_link_libraries(${BOT_NAME} | ||||
|     ${CMAKE_THREAD_LIBS_INIT} | ||||
|     ${OPENSSL_CRYPTO_LIBRARY}  | ||||
|     ${OPENSSL_SSL_LIBRARY} | ||||
|     ${Boost_LIBRARIES} | ||||
| ) | ||||
|  | ||||
| link_directories(/usr/lib) | ||||
							
								
								
									
										1303
									
								
								flamegraph.pl
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										1303
									
								
								flamegraph.pl
									
									
									
									
									
										Executable file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										67
									
								
								generateStackFlame.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										67
									
								
								generateStackFlame.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,67 @@ | ||||
| #!/bin/bash | ||||
|  | ||||
| # 기본값 설정 | ||||
| n_flag=20 | ||||
| i_flag=0 | ||||
| process_args=() | ||||
|  | ||||
| # 입력값 파싱 | ||||
| while [[ $# -gt 0 ]]; do | ||||
|     case "$1" in | ||||
|         -n) | ||||
|             shift | ||||
|             if [[ ! "$1" =~ ^[0-9]+$ ]]; then | ||||
|                 echo "오류: -n 옵션 뒤에는 숫자가 와야 합니다." >&2 | ||||
|                 exit 1 | ||||
|             fi | ||||
|             n_flag="$1" | ||||
|             ;; | ||||
|         -i) | ||||
|             shift | ||||
|             if [[ ! "$1" =~ ^[0-9]+$ ]]; then | ||||
|                 echo "오류: -i 옵션 뒤에는 숫자가 와야 합니다." >&2 | ||||
|                 exit 1 | ||||
|             fi | ||||
|             i_flag="$1" | ||||
|             ;; | ||||
|         *) | ||||
|             # 프로세스 명 또는 PID 검증 | ||||
|             if [[ "$1" =~ ^[0-9]+$ ]]; then | ||||
|                 # 숫자인 경우, PID 존재 여부 확인 | ||||
|                 if ! ps -p "$1" > /dev/null 2>&1; then | ||||
|                     echo "오류: PID $1 에 해당하는 프로세스가 존재하지 않습니다." >&2 | ||||
|                     exit 1 | ||||
|                 fi | ||||
|             else | ||||
|                 # 문자열인 경우, 프로세스 이름 존재 여부 확인 | ||||
|                 if ! pgrep -x "$1" > /dev/null 2>&1; then | ||||
|                     echo "오류: 프로세스 '$1' 가 실행 중이지 않습니다." >&2 | ||||
|                     exit 1 | ||||
|                 fi | ||||
|             fi | ||||
|             process_args+=("$1") | ||||
|             ;; | ||||
|     esac | ||||
|     shift | ||||
| done | ||||
|  | ||||
| # 프로세스 인자 검증 | ||||
| if [[ ${#process_args[@]} -eq 0 ]]; then | ||||
|     echo "오류: 최소한 하나 이상의 프로세스 이름 또는 PID를 입력해야 합니다." >&2 | ||||
|     exit 1 | ||||
| fi | ||||
|  | ||||
| pid=$(pidof $process_args) | ||||
|  | ||||
| for x in $(seq 1 $n_flag) | ||||
|     do | ||||
|         sudo gdb -ex "set pagination 0" \ | ||||
|                 -ex "thread apply all bt" \ | ||||
|                 -batch -p $pid >> out.gdb 2> /dev/null  | ||||
|         sleep $i_flag | ||||
|     done | ||||
|  | ||||
| ./stackcollapse-gdb.pl out.gdb > out.folded | ||||
| rm out.gdb | ||||
| ./flamegraph.pl out.folded > stackflame.svg | ||||
| rm out.folded | ||||
| @@ -2,6 +2,8 @@ | ||||
| #include <iostream> | ||||
| #include <sstream> | ||||
| #include <queue> | ||||
| #include <regex> | ||||
| #include <boost/process.hpp> | ||||
|  | ||||
| namespace bumbleBee { | ||||
| class ConsoleUtils { | ||||
| @@ -9,28 +11,36 @@ public: | ||||
|     /**  | ||||
|      * @brief 명령어를 쉘에서 실행하고 결과를 EOF 전까지 읽어 \n을 구분자로 토큰화하여 반환합니다 | ||||
|      * @param cmd 실행할 명령 | ||||
|      * @param args 아규먼트 | ||||
|      * @return std::queue<std::string> tokens | ||||
|      */ | ||||
|     static std::queue<std::string> getResultFromCommand(std::string cmd) { | ||||
|         std::string result, token; | ||||
|     static std::queue<std::string> safe_execute_command(const std::string& cmd, const std::vector<std::string>& args) { | ||||
|         std::queue<std::string> tokens; | ||||
|         FILE* stream; | ||||
|         const int maxBuffer = 12; // 적당한 크기 | ||||
|         char buffer[maxBuffer]; | ||||
|         cmd.append(" 2>&1"); // 표준에러를 표준출력으로 redirect | ||||
|         try { | ||||
|             boost::process::ipstream output;  // 명령의 출력을 받을 스트림 | ||||
|             boost::process::child c(cmd, boost::process::args(args), boost::process::std_out > output); | ||||
|  | ||||
|         stream = popen(cmd.c_str(), "r"); // 주어진 command를 shell로 실행하고 파이프 연결 (fd 반환) | ||||
|             if (stream) { | ||||
|                 while (fgets(buffer, maxBuffer, stream) != NULL) result.append(buffer); // fgets: fd (stream)를 길이 (maxBuffer)만큼 읽어 버퍼 (buffer)에 저장 | ||||
|                 pclose(stream); | ||||
|             } | ||||
|             std::string line; | ||||
|             while (!output.eof() && std::getline(output, line)) | ||||
|                 tokens.push(line); | ||||
|  | ||||
|         std::stringstream ss(result); | ||||
|         while (std::getline(ss, token, '\n')) { | ||||
|             tokens.push(token); | ||||
|             c.wait();  // 프로세스가 종료될 때까지 대기 | ||||
|             return tokens; | ||||
|         } catch (const std::exception& e) { | ||||
|             return tokens; | ||||
|         } | ||||
|     } | ||||
|     /**  | ||||
|      * @brief 명령어를 쉘에서 실행하고 결과를 파이프로 연결하여 반환합니다 | ||||
|      * @param cmd 실행할 명령 | ||||
|      * @param args 아규먼트 | ||||
|      * @return FILE* fd | ||||
|      */ | ||||
|     static FILE* safe_open_pipe(const std::string& cmd, const std::vector<std::string>& args) { | ||||
|         boost::process::pipe pipe; | ||||
|         boost::process::child c(cmd, boost::process::args(args), boost::process::std_out > pipe); | ||||
|  | ||||
|         return tokens; | ||||
|         return fdopen(pipe.native_source(), "r"); | ||||
|     } | ||||
| }; | ||||
| } | ||||
| @@ -7,7 +7,7 @@ namespace bumbleBee { | ||||
| class VersionsCheckUtils { | ||||
| public: | ||||
|     static bool isThereCMD(std::shared_ptr<dpp::cluster> cluster, std::string cmd) { | ||||
|         if (ConsoleUtils::getResultFromCommand("which " + cmd).size() == 0) { | ||||
|         if (ConsoleUtils::safe_execute_command("which", {cmd}).size() == 0) { | ||||
|             cluster->log(dpp::ll_error, cmd + " is unavaliable. unresolable error please install " + cmd); | ||||
|             return false; | ||||
|         } | ||||
| @@ -16,7 +16,7 @@ public: | ||||
|     } | ||||
|  | ||||
|     static void validateFFMPEG(std::shared_ptr<dpp::cluster> cluster) { | ||||
|         std::queue<std::string> result = ConsoleUtils::getResultFromCommand(SettingsManager::getFFMPEG_CMD() + " -version"); | ||||
|         std::queue<std::string> result = ConsoleUtils::safe_execute_command(SettingsManager::getFFMPEG_CMD(), {"-version"}); | ||||
|         std::string front = result.front(); | ||||
|         if (front[0] != 'f' || | ||||
|             front[1] != 'f' || | ||||
| @@ -43,7 +43,7 @@ public: | ||||
|     } | ||||
|  | ||||
|     static void validateYTDLP(std::shared_ptr<dpp::cluster> cluster) { | ||||
|         std::queue<std::string> result = ConsoleUtils::getResultFromCommand(SettingsManager::getYTDLP_CMD() + " --version"); | ||||
|         std::queue<std::string> result = ConsoleUtils::safe_execute_command(SettingsManager::getYTDLP_CMD(), {"--version"}); | ||||
|         std::string front = result.front(); | ||||
|         if ((front[0]-'0' < 0 || front[0]-'0' > 9) || | ||||
|             (front[1]-'0' < 0 || front[1]-'0' > 9) || | ||||
| @@ -72,7 +72,7 @@ public: | ||||
|  | ||||
|     static void updateytdlp(std::shared_ptr<dpp::cluster> cluster) { | ||||
|         cluster->log(dpp::ll_info, "Checking if yt-dlp update is available..."); | ||||
|         std::queue<std::string> result = ConsoleUtils::getResultFromCommand("./yt-dlp -U"); | ||||
|         std::queue<std::string> result = ConsoleUtils::safe_execute_command("./yt-dlp", {"-U"}); | ||||
|         while(!result.empty()) { | ||||
|             std::string front = result.front(); | ||||
|             result.pop(); | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
| #include <Settings/SettingsManager.hpp> | ||||
| #include <dpp/nlohmann/json.hpp> | ||||
| #include <Utils/QueuedMusicListEmbedProvider.hpp> | ||||
| #include <Utils/ConsoleUtils.hpp> | ||||
| #include <variant> | ||||
|  | ||||
| namespace bumbleBee::commands { | ||||
| @@ -23,12 +24,20 @@ namespace bumbleBee::commands { | ||||
|             return; | ||||
|         } | ||||
|         std::string query = std::get<std::string>(event.get_parameter("query")); | ||||
|         query = "\"" + query + "\""; | ||||
|         // query = "\"" + query + "\""; | ||||
|  | ||||
|         std::queue<std::string> ids = | ||||
|             ConsoleUtils::getResultFromCommand( | ||||
|             SettingsManager::getYTDLP_CMD() + | ||||
|             " --default-search ytsearch --flat-playlist --skip-download --quiet --ignore-errors --print id " + query); | ||||
|             ConsoleUtils::safe_execute_command( | ||||
|             SettingsManager::getYTDLP_CMD(), { | ||||
|             "--default-search", | ||||
|             "ytsearch", | ||||
|             "--flat-playlist", | ||||
|             "--skip-download", | ||||
|             "--quiet", | ||||
|             "--ignore-errors", | ||||
|             "--print", | ||||
|             "id", | ||||
|             query}); | ||||
|  | ||||
|         std::queue<std::shared_ptr<MusicQueueElement>> musics; | ||||
|  | ||||
| @@ -46,19 +55,18 @@ namespace bumbleBee::commands { | ||||
|                 ids.pop(); | ||||
|             } | ||||
|  | ||||
|             FILE* file = popen((SettingsManager::getYTDLP_CMD() + | ||||
|                 " --default-search ytsearch --flat-playlist --skip-download --quiet --ignore-errors -J http://youtu.be/" + ids.front()).c_str(), "r"); | ||||
|             std::string jsonData = ConsoleUtils::safe_execute_command(SettingsManager::getYTDLP_CMD(), { | ||||
|                 "--default-search", | ||||
|                 "ytsearch", | ||||
|                 "--flat-playlist", | ||||
|                 "--skip-download", | ||||
|                 "--quiet", | ||||
|                 "--ignore-errors", | ||||
|                 "-J", | ||||
|                 "http://youtu.be/" + ids.front() | ||||
|             }).front(); | ||||
|  | ||||
|             std::ostringstream oss; | ||||
|             char buffer[1024]; | ||||
|             size_t bytesRead; | ||||
|              | ||||
|             while ((bytesRead = fread(buffer, 1, sizeof(buffer), file)) > 0) { | ||||
|                 oss.write(buffer, bytesRead); | ||||
|             } | ||||
|             pclose(file); | ||||
|  | ||||
|             std::istringstream iss(oss.str()); | ||||
|             std::istringstream iss(jsonData); | ||||
|             nlohmann::json videoDataJson; | ||||
|             iss >> videoDataJson; | ||||
|  | ||||
| @@ -108,19 +116,18 @@ namespace bumbleBee::commands { | ||||
|                             continue; | ||||
|                         } | ||||
|  | ||||
|                         FILE* file = popen((SettingsManager::getYTDLP_CMD() + | ||||
|                             " --default-search ytsearch --flat-playlist --skip-download --quiet --ignore-errors -J http://youtu.be/" + ids.front()).c_str(), "r"); | ||||
|                         std::string jsonData = ConsoleUtils::safe_execute_command(SettingsManager::getYTDLP_CMD(), { | ||||
|                             "--default-search", | ||||
|                             "ytsearch", | ||||
|                             "--flat-playlist", | ||||
|                             "--skip-download", | ||||
|                             "--quiet", | ||||
|                             "--ignore-errors", | ||||
|                             "-J", | ||||
|                             "http://youtu.be/" + ids.front() | ||||
|                         }).front(); | ||||
|              | ||||
|                         std::ostringstream oss; | ||||
|                         char buffer[1024]; | ||||
|                         size_t bytesRead; | ||||
|                          | ||||
|                         while ((bytesRead = fread(buffer, 1, sizeof(buffer), file)) > 0) { | ||||
|                             oss.write(buffer, bytesRead); | ||||
|                         } | ||||
|                         pclose(file); | ||||
|  | ||||
|                         std::istringstream iss(oss.str()); | ||||
|                         std::istringstream iss(jsonData); | ||||
|                         nlohmann::json videoDataJson; | ||||
|                         iss >> videoDataJson; | ||||
|  | ||||
|   | ||||
| @@ -14,13 +14,19 @@ bool SettingsManager::REGISTER_COMMAND = false; | ||||
|  | ||||
| bool SettingsManager::validateToken() { | ||||
|     nlohmann::json response; | ||||
|     if (ConsoleUtils::getResultFromCommand("which curl").size() == 0) { | ||||
|     std::string curl = ConsoleUtils::safe_execute_command("/usr/bin/which", {"curl"}).front(); | ||||
|     if (curl == "") { | ||||
|         std::cout << "curl is unavaliable. unresolable error please install curl." << std::endl; | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     std::string stresult = ConsoleUtils::getResultFromCommand("curl -sX GET \"https://discord.com/api/v10/users/@me\" -H \"Authorization: Bot " + | ||||
|         TOKEN + "\"").front(); | ||||
|     std::string stresult = ConsoleUtils::safe_execute_command(curl, { | ||||
|         "-sX", | ||||
|         "GET", | ||||
|         "https://discord.com/api/v10/users/@me", | ||||
|         "-H", | ||||
|         "Authorization: Bot " + TOKEN + "" | ||||
|     }).front(); | ||||
|     std::stringstream ss(stresult); | ||||
|     ss >> response; | ||||
|  | ||||
|   | ||||
| @@ -38,8 +38,17 @@ void AsyncDownloadManager::downloadWorker() { | ||||
|         cluster->log(dpp::ll_info, "AsyncDownloadManager: " + query + " accepted."); | ||||
|  | ||||
|         std::queue<std::string> ids = | ||||
|             ConsoleUtils::getResultFromCommand(SettingsManager::getYTDLP_CMD() + | ||||
|             " --default-search ytsearch --flat-playlist --skip-download --quiet --ignore-errors --print id " + query); | ||||
|             ConsoleUtils::safe_execute_command( | ||||
|             SettingsManager::getYTDLP_CMD(), { | ||||
|             "--default-search", | ||||
|             "ytsearch", | ||||
|             "--flat-playlist", | ||||
|             "--skip-download", | ||||
|             "--quiet", | ||||
|             "--ignore-errors", | ||||
|             "--print", | ||||
|             "id", | ||||
|             query}); | ||||
|  | ||||
|         if (ids.size() >= 2) { | ||||
|             cluster->log(dpp::ll_info, query + " is playlist"); | ||||
| @@ -56,8 +65,13 @@ void AsyncDownloadManager::downloadWorker() { | ||||
|         } | ||||
|  | ||||
|         std::queue<std::string> urls = | ||||
|             ConsoleUtils::getResultFromCommand(SettingsManager::getYTDLP_CMD() + | ||||
|             " -f ba* --print urls https://youtu.be/" + ids.front()); | ||||
|             ConsoleUtils::safe_execute_command(SettingsManager::getYTDLP_CMD(), { | ||||
|             "-f", | ||||
|             "ba*", | ||||
|             "--print", | ||||
|             "urls", | ||||
|             "https://youtu.be/" + ids.front() | ||||
|         }); | ||||
|  | ||||
|         cluster->log(dpp::ll_debug, "url: " + urls.front()); | ||||
|  | ||||
| @@ -75,8 +89,11 @@ void AsyncDownloadManager::downloadWorker() { | ||||
|  | ||||
|             cluster->log(dpp::ll_info, "Thread id: " + tid.str() + ": " + downloadID + " accepted."); | ||||
|  | ||||
|             std::string command = std::string("./streamOpus.sh " + SettingsManager::getYTDLP_CMD() + " " + downloadID + " " + SettingsManager::getFFMPEG_CMD()); | ||||
|             stream = popen(command.c_str(), "r"); | ||||
|             stream = ConsoleUtils::safe_open_pipe("./streamOpus.sh", { | ||||
|                 SettingsManager::getYTDLP_CMD(), | ||||
|                 downloadID, | ||||
|                 SettingsManager::getFFMPEG_CMD() | ||||
|             }); | ||||
|  | ||||
|             cluster->log(dpp::ll_info, "Thread id: " + tid.str() + " Opened stream: " + downloadID); | ||||
|         }); | ||||
|   | ||||
							
								
								
									
										72
									
								
								stackcollapse-gdb.pl
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										72
									
								
								stackcollapse-gdb.pl
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,72 @@ | ||||
| #!/usr/bin/perl -ws | ||||
| # | ||||
| # stackcollapse-gdb  Collapse GDB backtraces | ||||
| # | ||||
| # Parse a list of GDB backtraces as generated with the poor man's | ||||
| # profiler [1]: | ||||
| # | ||||
| #   for x in $(seq 1 500); do | ||||
| #      gdb -ex "set pagination 0" -ex "thread apply all bt" -batch -p $pid 2> /dev/null | ||||
| #      sleep 0.01 | ||||
| #    done | ||||
| # | ||||
| # [1] http://poormansprofiler.org/ | ||||
| # | ||||
| # Copyright 2014 Gabriel Corona. All rights reserved. | ||||
| # | ||||
| # CDDL HEADER START | ||||
| # | ||||
| # The contents of this file are subject to the terms of the | ||||
| # Common Development and Distribution License (the "License"). | ||||
| # You may not use this file except in compliance with the License. | ||||
| # | ||||
| # You can obtain a copy of the license at docs/cddl1.txt or | ||||
| # http://opensource.org/licenses/CDDL-1.0. | ||||
| # See the License for the specific language governing permissions | ||||
| # and limitations under the License. | ||||
| # | ||||
| # When distributing Covered Code, include this CDDL HEADER in each | ||||
| # file and include the License file at docs/cddl1.txt. | ||||
| # If applicable, add the following below this CDDL HEADER, with the | ||||
| # fields enclosed by brackets "[]" replaced with your own identifying | ||||
| # information: Portions Copyright [yyyy] [name of copyright owner] | ||||
| # | ||||
| # CDDL HEADER END | ||||
|  | ||||
| use strict; | ||||
|  | ||||
| my $current = ""; | ||||
| my $previous_function = ""; | ||||
|  | ||||
| my %stacks; | ||||
|  | ||||
| while(<>) { | ||||
|   chomp; | ||||
|   if (m/^Thread/) { | ||||
|     $current="" | ||||
|   } | ||||
|   elsif(m/^#[0-9]* *([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*)/) { | ||||
|     my $function = $3; | ||||
|     my $alt = $1; | ||||
|     if(not($1 =~ /0x[a-zA-Z0-9]*/)) { | ||||
|       $function = $alt; | ||||
|     } | ||||
|     if ($current eq "") { | ||||
|       $current = $function; | ||||
|     } else { | ||||
|       $current = $function . ";" . $current; | ||||
|     } | ||||
|   } elsif(!($current eq "")) { | ||||
|     $stacks{$current} += 1; | ||||
|     $current = ""; | ||||
|   } | ||||
| } | ||||
|  | ||||
| if(!($current eq "")) { | ||||
|   $stacks{$current} += 1; | ||||
|   $current = ""; | ||||
| } | ||||
|  | ||||
| foreach my $k (sort { $a cmp $b } keys %stacks) { | ||||
|   print "$k $stacks{$k}\n"; | ||||
| } | ||||
							
								
								
									
										435
									
								
								stackcollapse-perf.pl
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										435
									
								
								stackcollapse-perf.pl
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,435 @@ | ||||
| #!/usr/bin/perl -w | ||||
| # | ||||
| # stackcollapse-perf.pl	collapse perf samples into single lines. | ||||
| # | ||||
| # Parses a list of multiline stacks generated by "perf script", and | ||||
| # outputs a semicolon separated stack followed by a space and a count. | ||||
| # If memory addresses (+0xd) are present, they are stripped, and resulting | ||||
| # identical stacks are colased with their counts summed. | ||||
| # | ||||
| # USAGE: ./stackcollapse-perf.pl [options] infile > outfile | ||||
| # | ||||
| # Run "./stackcollapse-perf.pl -h" to list options. | ||||
| # | ||||
| # Example input: | ||||
| # | ||||
| #  swapper     0 [000] 158665.570607: cpu-clock: | ||||
| #         ffffffff8103ce3b native_safe_halt ([kernel.kallsyms]) | ||||
| #         ffffffff8101c6a3 default_idle ([kernel.kallsyms]) | ||||
| #         ffffffff81013236 cpu_idle ([kernel.kallsyms]) | ||||
| #         ffffffff815bf03e rest_init ([kernel.kallsyms]) | ||||
| #         ffffffff81aebbfe start_kernel ([kernel.kallsyms].init.text) | ||||
| #  [...] | ||||
| # | ||||
| # Example output: | ||||
| # | ||||
| #  swapper;start_kernel;rest_init;cpu_idle;default_idle;native_safe_halt 1 | ||||
| # | ||||
| # Input may be created and processed using: | ||||
| # | ||||
| #  perf record -a -g -F 997 sleep 60 | ||||
| #  perf script | ./stackcollapse-perf.pl > out.stacks-folded | ||||
| # | ||||
| # The output of "perf script" should include stack traces. If these are missing | ||||
| # for you, try manually selecting the perf script output; eg: | ||||
| # | ||||
| #  perf script -f comm,pid,tid,cpu,time,event,ip,sym,dso,trace | ... | ||||
| # | ||||
| # This is also required for the --pid or --tid options, so that the output has | ||||
| # both the PID and TID. | ||||
| # | ||||
| # Copyright 2012 Joyent, Inc.  All rights reserved. | ||||
| # Copyright 2012 Brendan Gregg.  All rights reserved. | ||||
| # | ||||
| # CDDL HEADER START | ||||
| # | ||||
| # The contents of this file are subject to the terms of the | ||||
| # Common Development and Distribution License (the "License"). | ||||
| # You may not use this file except in compliance with the License. | ||||
| # | ||||
| # You can obtain a copy of the license at docs/cddl1.txt or | ||||
| # http://opensource.org/licenses/CDDL-1.0. | ||||
| # See the License for the specific language governing permissions | ||||
| # and limitations under the License. | ||||
| # | ||||
| # When distributing Covered Code, include this CDDL HEADER in each | ||||
| # file and include the License file at docs/cddl1.txt. | ||||
| # If applicable, add the following below this CDDL HEADER, with the | ||||
| # fields enclosed by brackets "[]" replaced with your own identifying | ||||
| # information: Portions Copyright [yyyy] [name of copyright owner] | ||||
| # | ||||
| # CDDL HEADER END | ||||
| # | ||||
| # 02-Mar-2012	Brendan Gregg	Created this. | ||||
| # 02-Jul-2014	   "	  "	Added process name to stacks. | ||||
|  | ||||
| use strict; | ||||
| use Getopt::Long; | ||||
|  | ||||
| my %collapsed; | ||||
|  | ||||
| sub remember_stack { | ||||
| 	my ($stack, $count) = @_; | ||||
| 	$collapsed{$stack} += $count; | ||||
| } | ||||
| my $annotate_kernel = 0; # put an annotation on kernel function | ||||
| my $annotate_jit = 0;   # put an annotation on jit symbols | ||||
| my $annotate_all = 0;   # enale all annotations | ||||
| my $include_pname = 1;	# include process names in stacks | ||||
| my $include_pid = 0;	# include process ID with process name | ||||
| my $include_tid = 0;	# include process & thread ID with process name | ||||
| my $include_addrs = 0;	# include raw address where a symbol can't be found | ||||
| my $tidy_java = 1;	# condense Java signatures | ||||
| my $tidy_generic = 1;	# clean up function names a little | ||||
| my $target_pname;	# target process name from perf invocation | ||||
| my $event_filter = "";    # event type filter, defaults to first encountered event | ||||
| my $event_defaulted = 0;  # whether we defaulted to an event (none provided) | ||||
| my $event_warning = 0;	  # if we printed a warning for the event | ||||
|  | ||||
| my $show_inline = 0; | ||||
| my $show_context = 0; | ||||
|  | ||||
| my $srcline_in_input = 0; # if there are extra lines with source location (perf script -F+srcline) | ||||
| GetOptions('inline' => \$show_inline, | ||||
|            'context' => \$show_context, | ||||
|            'srcline' => \$srcline_in_input, | ||||
|            'pid' => \$include_pid, | ||||
|            'kernel' => \$annotate_kernel, | ||||
|            'jit' => \$annotate_jit, | ||||
|            'all' => \$annotate_all, | ||||
|            'tid' => \$include_tid, | ||||
|            'addrs' => \$include_addrs, | ||||
|            'event-filter=s' => \$event_filter) | ||||
| or die <<USAGE_END; | ||||
| USAGE: $0 [options] infile > outfile\n | ||||
| 	--pid		# include PID with process names [1] | ||||
| 	--tid		# include TID and PID with process names [1] | ||||
| 	--inline	# un-inline using addr2line | ||||
| 	--all		# all annotations (--kernel --jit) | ||||
| 	--kernel	# annotate kernel functions with a _[k] | ||||
| 	--jit		# annotate jit functions with a _[j] | ||||
| 	--context	# adds source context to --inline | ||||
| 	--srcline	# parses output of 'perf script -F+srcline' and adds source context | ||||
| 	--addrs		# include raw addresses where symbols can't be found | ||||
| 	--event-filter=EVENT	# event name filter\n | ||||
| [1] perf script must emit both PID and TIDs for these to work; eg, Linux < 4.1: | ||||
| 	perf script -f comm,pid,tid,cpu,time,event,ip,sym,dso,trace | ||||
|     for Linux >= 4.1: | ||||
| 	perf script -F comm,pid,tid,cpu,time,event,ip,sym,dso,trace | ||||
|     If you save this output add --header on Linux >= 3.14 to include perf info. | ||||
| USAGE_END | ||||
|  | ||||
| if ($annotate_all) { | ||||
| 	$annotate_kernel = $annotate_jit = 1; | ||||
| } | ||||
|  | ||||
| my %inlineCache; | ||||
|  | ||||
| my %nmCache; | ||||
|  | ||||
| sub inlineCacheAdd { | ||||
| 	my ($pc, $mod, $result) = @_; | ||||
|    if (defined($inlineCache{$pc})) { | ||||
|       $inlineCache{$pc}{$mod} = $result; | ||||
|    } else { | ||||
|       $inlineCache{$pc} = {$mod => $result}; | ||||
|    } | ||||
| } | ||||
|  | ||||
| # for the --inline option | ||||
| sub inline { | ||||
| 	my ($pc, $rawfunc, $mod) = @_; | ||||
|  | ||||
| 	return $inlineCache{$pc}{$mod} if defined($inlineCache{$pc}{$mod}); | ||||
|  | ||||
| 	# capture addr2line output | ||||
| 	my $a2l_output = `addr2line -a $pc -e $mod -i -f -s -C`; | ||||
|  | ||||
| 	# remove first line | ||||
| 	$a2l_output =~ s/^(.*\n){1}//; | ||||
|  | ||||
| 	if ($a2l_output =~ /\?\?\n\?\?:0/) { | ||||
| 		# if addr2line fails and rawfunc is func+offset, then fall back to it | ||||
| 		if ($rawfunc =~ /^(.+)\+0x([0-9a-f]+)$/) { | ||||
| 			my $func = $1; | ||||
| 			my $addr = hex $2; | ||||
|  | ||||
| 			$nmCache{$mod}=`nm $mod` unless defined $nmCache{$mod}; | ||||
|  | ||||
| 			if ($nmCache{$mod} =~ /^([0-9a-f]+) . \Q$func\E$/m) { | ||||
| 			   my $base = hex $1; | ||||
| 				my $newPc = sprintf "0x%x", $base+$addr; | ||||
| 				my $result = inline($newPc, '', $mod); | ||||
| 				inlineCacheAdd($pc, $mod, $result); | ||||
| 				return $result; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	my @fullfunc; | ||||
| 	my $one_item = ""; | ||||
| 	for (split /^/, $a2l_output) { | ||||
| 		chomp $_; | ||||
|  | ||||
| 		# remove discriminator info if exists | ||||
| 		$_ =~ s/ \(discriminator \S+\)//; | ||||
|  | ||||
| 		if ($one_item eq "") { | ||||
| 			$one_item = $_; | ||||
| 		} else { | ||||
| 			if ($show_context == 1) { | ||||
| 				unshift @fullfunc, $one_item . ":$_"; | ||||
| 			} else { | ||||
| 				unshift @fullfunc, $one_item; | ||||
| 			} | ||||
| 			$one_item = ""; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	my $result = join ";" , @fullfunc; | ||||
|  | ||||
| 	inlineCacheAdd($pc, $mod, $result); | ||||
|  | ||||
| 	return $result; | ||||
| } | ||||
|  | ||||
| my @stack; | ||||
| my $pname; | ||||
| my $m_pid; | ||||
| my $m_tid; | ||||
| my $m_period; | ||||
|  | ||||
| # | ||||
| # Main loop | ||||
| # | ||||
| while (defined($_ = <>)) { | ||||
|  | ||||
| 	# find the name of the process launched by perf, by stepping backwards | ||||
| 	# over the args to find the first non-option (no dash): | ||||
| 	if (/^# cmdline/) { | ||||
| 		my @args = split ' ', $_; | ||||
| 		foreach my $arg (reverse @args) { | ||||
| 			if ($arg !~ /^-/) { | ||||
| 				$target_pname = $arg; | ||||
| 				$target_pname =~ s:.*/::;  # strip pathname | ||||
| 				last; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	# skip remaining comments | ||||
| 	next if m/^#/; | ||||
| 	chomp; | ||||
|  | ||||
| 	# end of stack. save cached data. | ||||
| 	if (m/^$/) { | ||||
| 		# ignore filtered samples | ||||
| 		next if not $pname; | ||||
|  | ||||
| 		if ($include_pname) { | ||||
| 			if (defined $pname) { | ||||
| 				unshift @stack, $pname; | ||||
| 			} else { | ||||
| 				unshift @stack, ""; | ||||
| 			} | ||||
| 		} | ||||
| 		remember_stack(join(";", @stack), $m_period) if @stack; | ||||
| 		undef @stack; | ||||
| 		undef $pname; | ||||
| 		next; | ||||
| 	} | ||||
|  | ||||
| 	# | ||||
| 	# event record start | ||||
| 	# | ||||
| 	if (/^(\S.+?)\s+(\d+)\/*(\d+)*\s+/) { | ||||
| 		# default "perf script" output has TID but not PID | ||||
| 		# eg, "java 25607 4794564.109216: 1 cycles:" | ||||
| 		# eg, "java 12688 [002] 6544038.708352: 235 cpu-clock:" | ||||
| 		# eg, "V8 WorkerThread 25607 4794564.109216: 104345 cycles:" | ||||
| 		# eg, "java 24636/25607 [000] 4794564.109216: 1 cycles:" | ||||
| 		# eg, "java 12688/12764 6544038.708352: 10309278 cpu-clock:" | ||||
| 		# eg, "V8 WorkerThread 24636/25607 [000] 94564.109216: 100 cycles:" | ||||
| 		# other combinations possible | ||||
| 		my ($comm, $pid, $tid, $period) = ($1, $2, $3, ""); | ||||
| 		if (not $tid) { | ||||
| 			$tid = $pid; | ||||
| 			$pid = "?"; | ||||
| 		} | ||||
|  | ||||
| 		if (/:\s*(\d+)*\s+(\S+):\s*$/) { | ||||
| 			$period = $1; | ||||
| 			my $event = $2; | ||||
|  | ||||
| 			if ($event_filter eq "") { | ||||
| 				# By default only show events of the first encountered | ||||
| 				# event type. Merging together different types, such as | ||||
| 				# instructions and cycles, produces misleading results. | ||||
| 				$event_filter = $event; | ||||
| 				$event_defaulted = 1; | ||||
| 			} elsif ($event ne $event_filter) { | ||||
| 				if ($event_defaulted and $event_warning == 0) { | ||||
| 					# only print this warning if necessary: | ||||
| 					# when we defaulted and there was | ||||
| 					# multiple event types. | ||||
| 					print STDERR "Filtering for events of type: $event\n"; | ||||
| 					$event_warning = 1; | ||||
| 				} | ||||
| 				next; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if (not $period) { | ||||
| 			$period = 1 | ||||
| 		} | ||||
| 		($m_pid, $m_tid, $m_period) = ($pid, $tid, $period); | ||||
|  | ||||
| 		if ($include_tid) { | ||||
| 			$pname = "$comm-$m_pid/$m_tid"; | ||||
| 		} elsif ($include_pid) { | ||||
| 			$pname = "$comm-$m_pid"; | ||||
| 		} else { | ||||
| 			$pname = "$comm"; | ||||
| 		} | ||||
| 		$pname =~ tr/ /_/; | ||||
|  | ||||
| 	# | ||||
| 	# stack line | ||||
| 	# | ||||
| 	} elsif (/^\s*(\w+)\s*(.+) \((.*)\)/) { | ||||
| 		# ignore filtered samples | ||||
| 		next if not $pname; | ||||
|  | ||||
| 		my ($pc, $rawfunc, $mod) = ($1, $2, $3); | ||||
|  | ||||
| 		if ($show_inline == 1 && $mod !~ m/(perf-\d+.map|kernel\.|\[[^\]]+\])/) { | ||||
| 			my $inlineRes = inline($pc, $rawfunc, $mod); | ||||
| 			# - empty result this happens e.g., when $mod does not exist or is a path to a compressed kernel module | ||||
| 			#   if this happens, the user will see error message from addr2line written to stderr | ||||
| 			# - if addr2line results in "??" , then it's much more sane to fall back than produce a '??' in graph | ||||
| 			if($inlineRes ne "" and $inlineRes ne "??" and $inlineRes ne "??:??:0" ) { | ||||
| 				unshift @stack, $inlineRes; | ||||
| 				next; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		# Linux 4.8 included symbol offsets in perf script output by default, eg: | ||||
| 		# 7fffb84c9afc cpu_startup_entry+0x800047c022ec ([kernel.kallsyms]) | ||||
| 		# strip these off: | ||||
| 		$rawfunc =~ s/\+0x[\da-f]+$//; | ||||
|  | ||||
| 		next if $rawfunc =~ /^\(/;		# skip process names | ||||
|  | ||||
| 		my $is_unknown=0; | ||||
| 		my @inline; | ||||
| 		for (split /\->/, $rawfunc) { | ||||
| 			my $func = $_; | ||||
|  | ||||
| 			if ($func eq "[unknown]") { | ||||
| 				if ($mod ne "[unknown]") { # use module name instead, if known | ||||
| 					$func = $mod; | ||||
| 					$func =~ s/.*\///; | ||||
| 				} else { | ||||
| 					$func = "unknown"; | ||||
| 					$is_unknown=1; | ||||
| 				} | ||||
|  | ||||
| 				if ($include_addrs) { | ||||
| 					$func = "\[$func \<$pc\>\]"; | ||||
| 				} else { | ||||
| 					$func = "\[$func\]"; | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			if ($tidy_generic) { | ||||
| 				$func =~ s/;/:/g; | ||||
| 				if ($func !~ m/\.\(.*\)\./) { | ||||
| 					# This doesn't look like a Go method name (such as | ||||
| 					# "net/http.(*Client).Do"), so everything after the first open | ||||
| 					# paren (that is not part of an "(anonymous namespace)") is | ||||
| 					# just noise. | ||||
| 					$func =~ s/\((?!anonymous namespace\)).*//; | ||||
| 				} | ||||
| 				# now tidy this horrible thing: | ||||
| 				# 13a80b608e0a RegExp:[&<>\"\'] (/tmp/perf-7539.map) | ||||
| 				$func =~ tr/"\'//d; | ||||
| 				# fall through to $tidy_java | ||||
| 			} | ||||
|  | ||||
| 			if ($tidy_java and $pname =~ m/^java/) { | ||||
| 				# along with $tidy_generic, converts the following: | ||||
| 				#	Lorg/mozilla/javascript/ContextFactory;.call(Lorg/mozilla/javascript/ContextAction;)Ljava/lang/Object; | ||||
| 				#	Lorg/mozilla/javascript/ContextFactory;.call(Lorg/mozilla/javascript/C | ||||
| 				#	Lorg/mozilla/javascript/MemberBox;.<init>(Ljava/lang/reflect/Method;)V | ||||
| 				# into: | ||||
| 				#	org/mozilla/javascript/ContextFactory:.call | ||||
| 				#	org/mozilla/javascript/ContextFactory:.call | ||||
| 				#	org/mozilla/javascript/MemberBox:.init | ||||
| 				$func =~ s/^L// if $func =~ m:/:; | ||||
| 			} | ||||
|  | ||||
| 			# | ||||
| 			# Annotations | ||||
| 			# | ||||
| 			# detect inlined from the @inline array | ||||
| 			# detect kernel from the module name; eg, frames to parse include: | ||||
| 			#          ffffffff8103ce3b native_safe_halt ([kernel.kallsyms])  | ||||
| 			#          8c3453 tcp_sendmsg (/lib/modules/4.3.0-rc1-virtual/build/vmlinux) | ||||
| 			#          7d8 ipv4_conntrack_local+0x7f8f80b8 ([nf_conntrack_ipv4]) | ||||
| 			# detect jit from the module name; eg: | ||||
| 			#          7f722d142778 Ljava/io/PrintStream;::print (/tmp/perf-19982.map) | ||||
| 			if (scalar(@inline) > 0) { | ||||
| 				$func .= "_[i]" unless $func =~ m/\_\[i\]/;	# inlined | ||||
| 			} elsif ($annotate_kernel == 1 && $mod =~ m/(^\[|vmlinux$)/ && $mod !~ /unknown/) { | ||||
| 				$func .= "_[k]";	# kernel | ||||
| 			} elsif ($annotate_jit == 1 && $mod =~ m:/tmp/perf-\d+\.map:) { | ||||
| 				$func .= "_[j]" unless $func =~ m/\_\[j\]/;	# jitted | ||||
| 			} | ||||
|  | ||||
| 			# | ||||
| 			# Source lines | ||||
| 			# | ||||
| 			# | ||||
| 			# Sample outputs: | ||||
| 			#   | a.out 35081 252436.005167:     667783 cycles: | ||||
| 			#   |                   408ebb some_method_name+0x8b (/full/path/to/a.out) | ||||
| 			#   |   uniform_int_dist.h:300 | ||||
| 			#   |                   4069f5 main+0x935 (/full/path/to/a.out) | ||||
| 			#   |   file.cpp:137 | ||||
| 			#   |             7f6d2148eb25 __libc_start_main+0xd5 (/lib64/libc-2.33.so) | ||||
| 			#   |   libc-2.33.so[27b25] | ||||
| 			# | ||||
| 			#   | a.out 35081 252435.738165:     306459 cycles: | ||||
| 			#   |             7f6d213c2750 [unknown] (/usr/lib64/libkmod.so.2.3.6) | ||||
| 			#   |   libkmod.so.2.3.6[6750] | ||||
| 			# | ||||
| 			#   | a.out 35081 252435.738373:     315813 cycles: | ||||
| 			#   |             7f6d215ca51b __strlen_avx2+0x4b (/lib64/libc-2.33.so) | ||||
| 			#   |   libc-2.33.so[16351b] | ||||
| 			#   |             7ffc71ee9580 [unknown] ([unknown])			 | ||||
| 			#   | | ||||
| 			# | ||||
| 			#   | a.out 35081 252435.718940:     247984 cycles: | ||||
| 			#   |         ffffffff814f9302 up_write+0x32 ([kernel.kallsyms]) | ||||
| 			#   |   [kernel.kallsyms][ffffffff814f9302] | ||||
| 			if($srcline_in_input and not $is_unknown){ | ||||
| 				$_ = <>; | ||||
| 				chomp; | ||||
| 				s/\[.*?\]//g; | ||||
| 				s/^\s*//g; | ||||
| 				s/\s*$//g; | ||||
| 				$func.=':'.$_ unless $_ eq ""; | ||||
| 			} | ||||
|  | ||||
| 			push @inline, $func; | ||||
| 		} | ||||
|  | ||||
| 		unshift @stack, @inline; | ||||
| 	} else { | ||||
| 		warn "Unrecognized line: $_"; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| foreach my $k (sort { $a cmp $b } keys %collapsed) { | ||||
| 	print "$k $collapsed{$k}\n"; | ||||
| } | ||||
							
								
								
									
										862
									
								
								stackflame.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										862
									
								
								stackflame.svg
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,862 @@ | ||||
| <?xml version="1.0" standalone="no"?> | ||||
| <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||||
| <svg version="1.1" width="1200" height="390" onload="init(evt)" viewBox="0 0 1200 390" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> | ||||
| <!-- Flame graph stack visualization. See https://github.com/brendangregg/FlameGraph for latest version, and http://www.brendangregg.com/flamegraphs.html for examples. --> | ||||
| <!-- NOTES:  --> | ||||
| <defs> | ||||
| 	<linearGradient id="background" y1="0" y2="1" x1="0" x2="0" > | ||||
| 		<stop stop-color="#eeeeee" offset="5%" /> | ||||
| 		<stop stop-color="#eeeeb0" offset="95%" /> | ||||
| 	</linearGradient> | ||||
| </defs> | ||||
| <style type="text/css"> | ||||
| 	text { font-family:Verdana; font-size:12px; fill:rgb(0,0,0); } | ||||
| 	#search, #ignorecase { opacity:0.1; cursor:pointer; } | ||||
| 	#search:hover, #search.show, #ignorecase:hover, #ignorecase.show { opacity:1; } | ||||
| 	#subtitle { text-anchor:middle; font-color:rgb(160,160,160); } | ||||
| 	#title { text-anchor:middle; font-size:17px} | ||||
| 	#unzoom { cursor:pointer; } | ||||
| 	#frames > *:hover { stroke:black; stroke-width:0.5; cursor:pointer; } | ||||
| 	.hide { display:none; } | ||||
| 	.parent { opacity:0.5; } | ||||
| </style> | ||||
| <script type="text/ecmascript"> | ||||
| <![CDATA[ | ||||
| 	"use strict"; | ||||
| 	var details, searchbtn, unzoombtn, matchedtxt, svg, searching, currentSearchTerm, ignorecase, ignorecaseBtn; | ||||
| 	function init(evt) { | ||||
| 		details = document.getElementById("details").firstChild; | ||||
| 		searchbtn = document.getElementById("search"); | ||||
| 		ignorecaseBtn = document.getElementById("ignorecase"); | ||||
| 		unzoombtn = document.getElementById("unzoom"); | ||||
| 		matchedtxt = document.getElementById("matched"); | ||||
| 		svg = document.getElementsByTagName("svg")[0]; | ||||
| 		searching = 0; | ||||
| 		currentSearchTerm = null; | ||||
|  | ||||
| 		// use GET parameters to restore a flamegraphs state. | ||||
| 		var params = get_params(); | ||||
| 		if (params.x && params.y) | ||||
| 			zoom(find_group(document.querySelector('[x="' + params.x + '"][y="' + params.y + '"]'))); | ||||
|                 if (params.s) search(params.s); | ||||
| 	} | ||||
|  | ||||
| 	// event listeners | ||||
| 	window.addEventListener("click", function(e) { | ||||
| 		var target = find_group(e.target); | ||||
| 		if (target) { | ||||
| 			if (target.nodeName == "a") { | ||||
| 				if (e.ctrlKey === false) return; | ||||
| 				e.preventDefault(); | ||||
| 			} | ||||
| 			if (target.classList.contains("parent")) unzoom(true); | ||||
| 			zoom(target); | ||||
| 			if (!document.querySelector('.parent')) { | ||||
| 				// we have basically done a clearzoom so clear the url | ||||
| 				var params = get_params(); | ||||
| 				if (params.x) delete params.x; | ||||
| 				if (params.y) delete params.y; | ||||
| 				history.replaceState(null, null, parse_params(params)); | ||||
| 				unzoombtn.classList.add("hide"); | ||||
| 				return; | ||||
| 			} | ||||
|  | ||||
| 			// set parameters for zoom state | ||||
| 			var el = target.querySelector("rect"); | ||||
| 			if (el && el.attributes && el.attributes.y && el.attributes._orig_x) { | ||||
| 				var params = get_params() | ||||
| 				params.x = el.attributes._orig_x.value; | ||||
| 				params.y = el.attributes.y.value; | ||||
| 				history.replaceState(null, null, parse_params(params)); | ||||
| 			} | ||||
| 		} | ||||
| 		else if (e.target.id == "unzoom") clearzoom(); | ||||
| 		else if (e.target.id == "search") search_prompt(); | ||||
| 		else if (e.target.id == "ignorecase") toggle_ignorecase(); | ||||
| 	}, false) | ||||
|  | ||||
| 	// mouse-over for info | ||||
| 	// show | ||||
| 	window.addEventListener("mouseover", function(e) { | ||||
| 		var target = find_group(e.target); | ||||
| 		if (target) details.nodeValue = "Function: " + g_to_text(target); | ||||
| 	}, false) | ||||
|  | ||||
| 	// clear | ||||
| 	window.addEventListener("mouseout", function(e) { | ||||
| 		var target = find_group(e.target); | ||||
| 		if (target) details.nodeValue = ' '; | ||||
| 	}, false) | ||||
|  | ||||
| 	// ctrl-F for search | ||||
| 	// ctrl-I to toggle case-sensitive search | ||||
| 	window.addEventListener("keydown",function (e) { | ||||
| 		if (e.keyCode === 114 || (e.ctrlKey && e.keyCode === 70)) { | ||||
| 			e.preventDefault(); | ||||
| 			search_prompt(); | ||||
| 		} | ||||
| 		else if (e.ctrlKey && e.keyCode === 73) { | ||||
| 			e.preventDefault(); | ||||
| 			toggle_ignorecase(); | ||||
| 		} | ||||
| 	}, false) | ||||
|  | ||||
| 	// functions | ||||
| 	function get_params() { | ||||
| 		var params = {}; | ||||
| 		var paramsarr = window.location.search.substr(1).split('&'); | ||||
| 		for (var i = 0; i < paramsarr.length; ++i) { | ||||
| 			var tmp = paramsarr[i].split("="); | ||||
| 			if (!tmp[0] || !tmp[1]) continue; | ||||
| 			params[tmp[0]]  = decodeURIComponent(tmp[1]); | ||||
| 		} | ||||
| 		return params; | ||||
| 	} | ||||
| 	function parse_params(params) { | ||||
| 		var uri = "?"; | ||||
| 		for (var key in params) { | ||||
| 			uri += key + '=' + encodeURIComponent(params[key]) + '&'; | ||||
| 		} | ||||
| 		if (uri.slice(-1) == "&") | ||||
| 			uri = uri.substring(0, uri.length - 1); | ||||
| 		if (uri == '?') | ||||
| 			uri = window.location.href.split('?')[0]; | ||||
| 		return uri; | ||||
| 	} | ||||
| 	function find_child(node, selector) { | ||||
| 		var children = node.querySelectorAll(selector); | ||||
| 		if (children.length) return children[0]; | ||||
| 	} | ||||
| 	function find_group(node) { | ||||
| 		var parent = node.parentElement; | ||||
| 		if (!parent) return; | ||||
| 		if (parent.id == "frames") return node; | ||||
| 		return find_group(parent); | ||||
| 	} | ||||
| 	function orig_save(e, attr, val) { | ||||
| 		if (e.attributes["_orig_" + attr] != undefined) return; | ||||
| 		if (e.attributes[attr] == undefined) return; | ||||
| 		if (val == undefined) val = e.attributes[attr].value; | ||||
| 		e.setAttribute("_orig_" + attr, val); | ||||
| 	} | ||||
| 	function orig_load(e, attr) { | ||||
| 		if (e.attributes["_orig_"+attr] == undefined) return; | ||||
| 		e.attributes[attr].value = e.attributes["_orig_" + attr].value; | ||||
| 		e.removeAttribute("_orig_"+attr); | ||||
| 	} | ||||
| 	function g_to_text(e) { | ||||
| 		var text = find_child(e, "title").firstChild.nodeValue; | ||||
| 		return (text) | ||||
| 	} | ||||
| 	function g_to_func(e) { | ||||
| 		var func = g_to_text(e); | ||||
| 		// if there's any manipulation we want to do to the function | ||||
| 		// name before it's searched, do it here before returning. | ||||
| 		return (func); | ||||
| 	} | ||||
| 	function update_text(e) { | ||||
| 		var r = find_child(e, "rect"); | ||||
| 		var t = find_child(e, "text"); | ||||
| 		var w = parseFloat(r.attributes.width.value) -3; | ||||
| 		var txt = find_child(e, "title").textContent.replace(/\([^(]*\)$/,""); | ||||
| 		t.attributes.x.value = parseFloat(r.attributes.x.value) + 3; | ||||
|  | ||||
| 		// Smaller than this size won't fit anything | ||||
| 		if (w < 2 * 12 * 0.59) { | ||||
| 			t.textContent = ""; | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		t.textContent = txt; | ||||
| 		var sl = t.getSubStringLength(0, txt.length); | ||||
| 		// check if only whitespace or if we can fit the entire string into width w | ||||
| 		if (/^ *$/.test(txt) || sl < w) | ||||
| 			return; | ||||
|  | ||||
| 		// this isn't perfect, but gives a good starting point | ||||
| 		// and avoids calling getSubStringLength too often | ||||
| 		var start = Math.floor((w/sl) * txt.length); | ||||
| 		for (var x = start; x > 0; x = x-2) { | ||||
| 			if (t.getSubStringLength(0, x + 2) <= w) { | ||||
| 				t.textContent = txt.substring(0, x) + ".."; | ||||
| 				return; | ||||
| 			} | ||||
| 		} | ||||
| 		t.textContent = ""; | ||||
| 	} | ||||
|  | ||||
| 	// zoom | ||||
| 	function zoom_reset(e) { | ||||
| 		if (e.attributes != undefined) { | ||||
| 			orig_load(e, "x"); | ||||
| 			orig_load(e, "width"); | ||||
| 		} | ||||
| 		if (e.childNodes == undefined) return; | ||||
| 		for (var i = 0, c = e.childNodes; i < c.length; i++) { | ||||
| 			zoom_reset(c[i]); | ||||
| 		} | ||||
| 	} | ||||
| 	function zoom_child(e, x, ratio) { | ||||
| 		if (e.attributes != undefined) { | ||||
| 			if (e.attributes.x != undefined) { | ||||
| 				orig_save(e, "x"); | ||||
| 				e.attributes.x.value = (parseFloat(e.attributes.x.value) - x - 10) * ratio + 10; | ||||
| 				if (e.tagName == "text") | ||||
| 					e.attributes.x.value = find_child(e.parentNode, "rect[x]").attributes.x.value + 3; | ||||
| 			} | ||||
| 			if (e.attributes.width != undefined) { | ||||
| 				orig_save(e, "width"); | ||||
| 				e.attributes.width.value = parseFloat(e.attributes.width.value) * ratio; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if (e.childNodes == undefined) return; | ||||
| 		for (var i = 0, c = e.childNodes; i < c.length; i++) { | ||||
| 			zoom_child(c[i], x - 10, ratio); | ||||
| 		} | ||||
| 	} | ||||
| 	function zoom_parent(e) { | ||||
| 		if (e.attributes) { | ||||
| 			if (e.attributes.x != undefined) { | ||||
| 				orig_save(e, "x"); | ||||
| 				e.attributes.x.value = 10; | ||||
| 			} | ||||
| 			if (e.attributes.width != undefined) { | ||||
| 				orig_save(e, "width"); | ||||
| 				e.attributes.width.value = parseInt(svg.width.baseVal.value) - (10 * 2); | ||||
| 			} | ||||
| 		} | ||||
| 		if (e.childNodes == undefined) return; | ||||
| 		for (var i = 0, c = e.childNodes; i < c.length; i++) { | ||||
| 			zoom_parent(c[i]); | ||||
| 		} | ||||
| 	} | ||||
| 	function zoom(node) { | ||||
| 		var attr = find_child(node, "rect").attributes; | ||||
| 		var width = parseFloat(attr.width.value); | ||||
| 		var xmin = parseFloat(attr.x.value); | ||||
| 		var xmax = parseFloat(xmin + width); | ||||
| 		var ymin = parseFloat(attr.y.value); | ||||
| 		var ratio = (svg.width.baseVal.value - 2 * 10) / width; | ||||
|  | ||||
| 		// XXX: Workaround for JavaScript float issues (fix me) | ||||
| 		var fudge = 0.0001; | ||||
|  | ||||
| 		unzoombtn.classList.remove("hide"); | ||||
|  | ||||
| 		var el = document.getElementById("frames").children; | ||||
| 		for (var i = 0; i < el.length; i++) { | ||||
| 			var e = el[i]; | ||||
| 			var a = find_child(e, "rect").attributes; | ||||
| 			var ex = parseFloat(a.x.value); | ||||
| 			var ew = parseFloat(a.width.value); | ||||
| 			var upstack; | ||||
| 			// Is it an ancestor | ||||
| 			if (0 == 0) { | ||||
| 				upstack = parseFloat(a.y.value) > ymin; | ||||
| 			} else { | ||||
| 				upstack = parseFloat(a.y.value) < ymin; | ||||
| 			} | ||||
| 			if (upstack) { | ||||
| 				// Direct ancestor | ||||
| 				if (ex <= xmin && (ex+ew+fudge) >= xmax) { | ||||
| 					e.classList.add("parent"); | ||||
| 					zoom_parent(e); | ||||
| 					update_text(e); | ||||
| 				} | ||||
| 				// not in current path | ||||
| 				else | ||||
| 					e.classList.add("hide"); | ||||
| 			} | ||||
| 			// Children maybe | ||||
| 			else { | ||||
| 				// no common path | ||||
| 				if (ex < xmin || ex + fudge >= xmax) { | ||||
| 					e.classList.add("hide"); | ||||
| 				} | ||||
| 				else { | ||||
| 					zoom_child(e, xmin, ratio); | ||||
| 					update_text(e); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		search(); | ||||
| 	} | ||||
| 	function unzoom(dont_update_text) { | ||||
| 		unzoombtn.classList.add("hide"); | ||||
| 		var el = document.getElementById("frames").children; | ||||
| 		for(var i = 0; i < el.length; i++) { | ||||
| 			el[i].classList.remove("parent"); | ||||
| 			el[i].classList.remove("hide"); | ||||
| 			zoom_reset(el[i]); | ||||
| 			if(!dont_update_text) update_text(el[i]); | ||||
| 		} | ||||
| 		search(); | ||||
| 	} | ||||
| 	function clearzoom() { | ||||
| 		unzoom(); | ||||
|  | ||||
| 		// remove zoom state | ||||
| 		var params = get_params(); | ||||
| 		if (params.x) delete params.x; | ||||
| 		if (params.y) delete params.y; | ||||
| 		history.replaceState(null, null, parse_params(params)); | ||||
| 	} | ||||
|  | ||||
| 	// search | ||||
| 	function toggle_ignorecase() { | ||||
| 		ignorecase = !ignorecase; | ||||
| 		if (ignorecase) { | ||||
| 			ignorecaseBtn.classList.add("show"); | ||||
| 		} else { | ||||
| 			ignorecaseBtn.classList.remove("show"); | ||||
| 		} | ||||
| 		reset_search(); | ||||
| 		search(); | ||||
| 	} | ||||
| 	function reset_search() { | ||||
| 		var el = document.querySelectorAll("#frames rect"); | ||||
| 		for (var i = 0; i < el.length; i++) { | ||||
| 			orig_load(el[i], "fill") | ||||
| 		} | ||||
| 		var params = get_params(); | ||||
| 		delete params.s; | ||||
| 		history.replaceState(null, null, parse_params(params)); | ||||
| 	} | ||||
| 	function search_prompt() { | ||||
| 		if (!searching) { | ||||
| 			var term = prompt("Enter a search term (regexp " + | ||||
| 			    "allowed, eg: ^ext4_)" | ||||
| 			    + (ignorecase ? ", ignoring case" : "") | ||||
| 			    + "\nPress Ctrl-i to toggle case sensitivity", ""); | ||||
| 			if (term != null) search(term); | ||||
| 		} else { | ||||
| 			reset_search(); | ||||
| 			searching = 0; | ||||
| 			currentSearchTerm = null; | ||||
| 			searchbtn.classList.remove("show"); | ||||
| 			searchbtn.firstChild.nodeValue = "Search" | ||||
| 			matchedtxt.classList.add("hide"); | ||||
| 			matchedtxt.firstChild.nodeValue = "" | ||||
| 		} | ||||
| 	} | ||||
| 	function search(term) { | ||||
| 		if (term) currentSearchTerm = term; | ||||
| 		if (currentSearchTerm === null) return; | ||||
|  | ||||
| 		var re = new RegExp(currentSearchTerm, ignorecase ? 'i' : ''); | ||||
| 		var el = document.getElementById("frames").children; | ||||
| 		var matches = new Object(); | ||||
| 		var maxwidth = 0; | ||||
| 		for (var i = 0; i < el.length; i++) { | ||||
| 			var e = el[i]; | ||||
| 			var func = g_to_func(e); | ||||
| 			var rect = find_child(e, "rect"); | ||||
| 			if (func == null || rect == null) | ||||
| 				continue; | ||||
|  | ||||
| 			// Save max width. Only works as we have a root frame | ||||
| 			var w = parseFloat(rect.attributes.width.value); | ||||
| 			if (w > maxwidth) | ||||
| 				maxwidth = w; | ||||
|  | ||||
| 			if (func.match(re)) { | ||||
| 				// highlight | ||||
| 				var x = parseFloat(rect.attributes.x.value); | ||||
| 				orig_save(rect, "fill"); | ||||
| 				rect.attributes.fill.value = "rgb(230,0,230)"; | ||||
|  | ||||
| 				// remember matches | ||||
| 				if (matches[x] == undefined) { | ||||
| 					matches[x] = w; | ||||
| 				} else { | ||||
| 					if (w > matches[x]) { | ||||
| 						// overwrite with parent | ||||
| 						matches[x] = w; | ||||
| 					} | ||||
| 				} | ||||
| 				searching = 1; | ||||
| 			} | ||||
| 		} | ||||
| 		if (!searching) | ||||
| 			return; | ||||
| 		var params = get_params(); | ||||
| 		params.s = currentSearchTerm; | ||||
| 		history.replaceState(null, null, parse_params(params)); | ||||
|  | ||||
| 		searchbtn.classList.add("show"); | ||||
| 		searchbtn.firstChild.nodeValue = "Reset Search"; | ||||
|  | ||||
| 		// calculate percent matched, excluding vertical overlap | ||||
| 		var count = 0; | ||||
| 		var lastx = -1; | ||||
| 		var lastw = 0; | ||||
| 		var keys = Array(); | ||||
| 		for (k in matches) { | ||||
| 			if (matches.hasOwnProperty(k)) | ||||
| 				keys.push(k); | ||||
| 		} | ||||
| 		// sort the matched frames by their x location | ||||
| 		// ascending, then width descending | ||||
| 		keys.sort(function(a, b){ | ||||
| 			return a - b; | ||||
| 		}); | ||||
| 		// Step through frames saving only the biggest bottom-up frames | ||||
| 		// thanks to the sort order. This relies on the tree property | ||||
| 		// where children are always smaller than their parents. | ||||
| 		var fudge = 0.0001;	// JavaScript floating point | ||||
| 		for (var k in keys) { | ||||
| 			var x = parseFloat(keys[k]); | ||||
| 			var w = matches[keys[k]]; | ||||
| 			if (x >= lastx + lastw - fudge) { | ||||
| 				count += w; | ||||
| 				lastx = x; | ||||
| 				lastw = w; | ||||
| 			} | ||||
| 		} | ||||
| 		// display matched percent | ||||
| 		matchedtxt.classList.remove("hide"); | ||||
| 		var pct = 100 * count / maxwidth; | ||||
| 		if (pct != 100) pct = pct.toFixed(1) | ||||
| 		matchedtxt.firstChild.nodeValue = "Matched: " + pct + "%"; | ||||
| 	} | ||||
| ]]> | ||||
| </script> | ||||
| <rect x="0.0" y="0" width="1200.0" height="390.0" fill="url(#background)"  /> | ||||
| <text id="title" x="600.00" y="24" >Flame Graph</text> | ||||
| <text id="details" x="10.00" y="373" > </text> | ||||
| <text id="unzoom" x="10.00" y="24" class="hide">Reset Zoom</text> | ||||
| <text id="search" x="1090.00" y="24" >Search</text> | ||||
| <text id="ignorecase" x="1174.00" y="24" >ic</text> | ||||
| <text id="matched" x="1090.00" y="373" > </text> | ||||
| <g id="frames"> | ||||
| <g > | ||||
| <title>_IO_new_file_underflow (2 samples, 0.52%)</title><rect x="1122.4" y="101" width="6.1" height="15.0" fill="rgb(214,42,10)" rx="2" ry="2" /> | ||||
| <text  x="1125.40" y="111.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>dpp::ssl_client::read_loop() (4 samples, 1.04%)</title><rect x="919.6" y="213" width="12.3" height="15.0" fill="rgb(243,175,41)" rx="2" ry="2" /> | ||||
| <text  x="922.58" y="223.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>lll_mutex_lock_optimized (1 samples, 0.26%)</title><rect x="117.6" y="213" width="3.0" height="15.0" fill="rgb(209,22,5)" rx="2" ry="2" /> | ||||
| <text  x="120.55" y="223.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>dpp::https_client::connect() (4 samples, 1.04%)</title><rect x="919.6" y="229" width="12.3" height="15.0" fill="rgb(251,211,50)" rx="2" ry="2" /> | ||||
| <text  x="922.58" y="239.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>___pthread_cond_wait (20 samples, 5.21%)</title><rect x="1128.5" y="277" width="61.5" height="15.0" fill="rgb(252,219,52)" rx="2" ry="2" /> | ||||
| <text  x="1131.54" y="287.5" >___pth..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>___pthread_mutex_lock (1 samples, 0.26%)</title><rect x="117.6" y="229" width="3.0" height="15.0" fill="rgb(206,7,1)" rx="2" ry="2" /> | ||||
| <text  x="120.55" y="239.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>all (384 samples, 100%)</title><rect x="10.0" y="341" width="1180.0" height="15.0" fill="rgb(213,39,9)" rx="2" ry="2" /> | ||||
| <text  x="13.00" y="351.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__GI___underflow (2 samples, 0.52%)</title><rect x="1122.4" y="117" width="6.1" height="15.0" fill="rgb(221,74,17)" rx="2" ry="2" /> | ||||
| <text  x="1125.40" y="127.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>nlohmann::json_abi_v3_11_2::detail::parser<nlohmann::json_abi_v3_11_2::basic_json<std::map, (1 samples, 0.26%)</title><rect x="1079.4" y="149" width="3.0" height="15.0" fill="rgb(217,59,14)" rx="2" ry="2" /> | ||||
| <text  x="1082.38" y="159.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__futex_abstimed_wait_common (256 samples, 66.67%)</title><rect x="132.9" y="197" width="786.7" height="15.0" fill="rgb(205,0,0)" rx="2" ry="2" /> | ||||
| <text  x="135.92" y="207.5" >__futex_abstimed_wait_common</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>___pthread_cond_clockwait64 (40 samples, 10.42%)</title><rect x="931.9" y="261" width="122.9" height="15.0" fill="rgb(233,129,30)" rx="2" ry="2" /> | ||||
| <text  x="934.88" y="271.5" >___pthread_cond..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>?? (2 samples, 0.52%)</title><rect x="1122.4" y="165" width="6.1" height="15.0" fill="rgb(249,205,49)" rx="2" ry="2" /> | ||||
| <text  x="1125.40" y="175.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__GI___libc_free (1 samples, 0.26%)</title><rect x="1054.8" y="133" width="3.1" height="15.0" fill="rgb(252,218,52)" rx="2" ry="2" /> | ||||
| <text  x="1057.79" y="143.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>_IO_new_file_underflow (3 samples, 0.78%)</title><rect x="1057.9" y="117" width="9.2" height="15.0" fill="rgb(214,42,10)" rx="2" ry="2" /> | ||||
| <text  x="1060.86" y="127.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>std::thread::_Invoker<std::tuple<bumbleBee::MusicPlayManager::play(dpp::discord_voice_client*)::<lambda(dpp::discord_voice_client*)>, (13 samples, 3.39%)</title><rect x="1082.4" y="261" width="40.0" height="15.0" fill="rgb(208,13,3)" rx="2" ry="2" /> | ||||
| <text  x="1085.45" y="271.5" >std..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__GI__IO_fread (3 samples, 0.78%)</title><rect x="1057.9" y="165" width="9.2" height="15.0" fill="rgb(212,34,8)" rx="2" ry="2" /> | ||||
| <text  x="1060.86" y="175.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>bumbleBee::MusicPlayManager::remove (1 samples, 0.26%)</title><rect x="1054.8" y="165" width="3.1" height="15.0" fill="rgb(230,117,28)" rx="2" ry="2" /> | ||||
| <text  x="1057.79" y="175.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__GI__IO_default_xsgetn (3 samples, 0.78%)</title><rect x="1057.9" y="149" width="9.2" height="15.0" fill="rgb(236,145,34)" rx="2" ry="2" /> | ||||
| <text  x="1060.86" y="159.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>___pthread_cond_clockwait64 (40 samples, 10.42%)</title><rect x="931.9" y="245" width="122.9" height="15.0" fill="rgb(233,129,30)" rx="2" ry="2" /> | ||||
| <text  x="934.88" y="255.5" >___pthread_cond..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__GI__IO_getline (4 samples, 1.04%)</title><rect x="1067.1" y="133" width="12.3" height="15.0" fill="rgb(226,100,23)" rx="2" ry="2" /> | ||||
| <text  x="1070.08" y="143.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>_int_free (1 samples, 0.26%)</title><rect x="1054.8" y="117" width="3.1" height="15.0" fill="rgb(247,196,46)" rx="2" ry="2" /> | ||||
| <text  x="1057.79" y="127.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__GI___libc_read (2 samples, 0.52%)</title><rect x="1122.4" y="69" width="6.1" height="15.0" fill="rgb(241,166,39)" rx="2" ry="2" /> | ||||
| <text  x="1125.40" y="79.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>dpp::in_thread::in_loop(unsigned (260 samples, 67.71%)</title><rect x="132.9" y="277" width="799.0" height="15.0" fill="rgb(208,15,3)" rx="2" ry="2" /> | ||||
| <text  x="135.92" y="287.5" >dpp::in_thread::in_loop(unsigned</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>bumbleBee::BumbleBee::start (20 samples, 5.21%)</title><rect x="1128.5" y="309" width="61.5" height="15.0" fill="rgb(252,216,51)" rx="2" ry="2" /> | ||||
| <text  x="1131.54" y="319.5" >bumble..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__futex_abstimed_wait_common64 (13 samples, 3.39%)</title><rect x="1082.4" y="101" width="40.0" height="15.0" fill="rgb(220,71,17)" rx="2" ry="2" /> | ||||
| <text  x="1085.45" y="111.5" >__f..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>dpp::discord_voice_client::write_ready() (4 samples, 1.04%)</title><rect x="120.6" y="245" width="12.3" height="15.0" fill="rgb(245,186,44)" rx="2" ry="2" /> | ||||
| <text  x="123.62" y="255.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>operator() (2 samples, 0.52%)</title><rect x="1122.4" y="197" width="6.1" height="15.0" fill="rgb(231,121,29)" rx="2" ry="2" /> | ||||
| <text  x="1125.40" y="207.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__pthread_cond_wait_common (40 samples, 10.42%)</title><rect x="931.9" y="229" width="122.9" height="15.0" fill="rgb(210,24,5)" rx="2" ry="2" /> | ||||
| <text  x="934.88" y="239.5" >__pthread_cond_..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__GI__IO_default_xsgetn (2 samples, 0.52%)</title><rect x="1122.4" y="133" width="6.1" height="15.0" fill="rgb(236,145,34)" rx="2" ry="2" /> | ||||
| <text  x="1125.40" y="143.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>nlohmann::json_abi_v3_11_2::operator>> (1 samples, 0.26%)</title><rect x="1079.4" y="165" width="3.0" height="15.0" fill="rgb(210,23,5)" rx="2" ry="2" /> | ||||
| <text  x="1082.38" y="175.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__futex_abstimed_wait_common (40 samples, 10.42%)</title><rect x="931.9" y="197" width="122.9" height="15.0" fill="rgb(205,0,0)" rx="2" ry="2" /> | ||||
| <text  x="934.88" y="207.5" >__futex_abstime..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>___pthread_cond_wait (13 samples, 3.39%)</title><rect x="1082.4" y="165" width="40.0" height="15.0" fill="rgb(252,219,52)" rx="2" ry="2" /> | ||||
| <text  x="1085.45" y="175.5" >___..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>std::__invoke_impl<void, (13 samples, 3.39%)</title><rect x="1082.4" y="213" width="40.0" height="15.0" fill="rgb(244,179,42)" rx="2" ry="2" /> | ||||
| <text  x="1085.45" y="223.5" >std..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>main (20 samples, 5.21%)</title><rect x="1128.5" y="325" width="61.5" height="15.0" fill="rgb(243,179,42)" rx="2" ry="2" /> | ||||
| <text  x="1131.54" y="335.5" >main</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>std::thread::_Invoker<std::tuple<bumbleBee::BumbleBee::on_slashcommand(const (9 samples, 2.34%)</title><rect x="1054.8" y="245" width="27.6" height="15.0" fill="rgb(251,213,50)" rx="2" ry="2" /> | ||||
| <text  x="1057.79" y="255.5" >s..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>std::__invoke<bumbleBee::MusicPlayManager::send_audio_to_voice(std::shared_ptr<bumbleBee::MusicQueueElement>, (2 samples, 0.52%)</title><rect x="1122.4" y="229" width="6.1" height="15.0" fill="rgb(217,59,14)" rx="2" ry="2" /> | ||||
| <text  x="1125.40" y="239.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>dpp::request_queue::out_loop() (40 samples, 10.42%)</title><rect x="931.9" y="277" width="122.9" height="15.0" fill="rgb(227,105,25)" rx="2" ry="2" /> | ||||
| <text  x="934.88" y="287.5" >dpp::request_qu..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>std::thread::_Invoker<std::tuple<bumbleBee::MusicPlayManager::send_audio_to_voice(std::shared_ptr<bumbleBee::MusicQueueElement>, (2 samples, 0.52%)</title><rect x="1122.4" y="245" width="6.1" height="15.0" fill="rgb(216,50,12)" rx="2" ry="2" /> | ||||
| <text  x="1125.40" y="255.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>std::__invoke_impl<void, (9 samples, 2.34%)</title><rect x="1054.8" y="213" width="27.6" height="15.0" fill="rgb(244,179,42)" rx="2" ry="2" /> | ||||
| <text  x="1057.79" y="223.5" >s..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>std::thread::_Invoker<std::tuple<bumbleBee::BumbleBee::on_slashcommand(const (9 samples, 2.34%)</title><rect x="1054.8" y="261" width="27.6" height="15.0" fill="rgb(251,213,50)" rx="2" ry="2" /> | ||||
| <text  x="1057.79" y="271.5" >s..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>std::thread::_State_impl<std::thread::_Invoker<std::tuple<bumbleBee::MusicPlayManager::play(dpp::discord_voice_client*)::<lambda(dpp::discord_voice_client*)>, (13 samples, 3.39%)</title><rect x="1082.4" y="277" width="40.0" height="15.0" fill="rgb(205,4,1)" rx="2" ry="2" /> | ||||
| <text  x="1085.45" y="287.5" >std..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>bumbleBee::commands::Play::execute (8 samples, 2.08%)</title><rect x="1057.9" y="181" width="24.5" height="15.0" fill="rgb(217,56,13)" rx="2" ry="2" /> | ||||
| <text  x="1060.86" y="191.5" >b..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__GI___poll (20 samples, 5.21%)</title><rect x="10.0" y="245" width="61.5" height="15.0" fill="rgb(228,110,26)" rx="2" ry="2" /> | ||||
| <text  x="13.00" y="255.5" >__GI__..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>_IO_fgets (4 samples, 1.04%)</title><rect x="1067.1" y="149" width="12.3" height="15.0" fill="rgb(235,139,33)" rx="2" ry="2" /> | ||||
| <text  x="1070.08" y="159.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>std::__invoke<bumbleBee::MusicPlayManager::play(dpp::discord_voice_client*)::<lambda(dpp::discord_voice_client*)>, (13 samples, 3.39%)</title><rect x="1082.4" y="229" width="40.0" height="15.0" fill="rgb(209,22,5)" rx="2" ry="2" /> | ||||
| <text  x="1085.45" y="239.5" >std..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>std::thread::_State_impl<std::thread::_Invoker<std::tuple<bumbleBee::MusicPlayManager::send_audio_to_voice(std::shared_ptr<bumbleBee::MusicQueueElement>, (2 samples, 0.52%)</title><rect x="1122.4" y="277" width="6.1" height="15.0" fill="rgb(213,41,9)" rx="2" ry="2" /> | ||||
| <text  x="1125.40" y="287.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__GI___libc_read (2 samples, 0.52%)</title><rect x="1122.4" y="85" width="6.1" height="15.0" fill="rgb(241,166,39)" rx="2" ry="2" /> | ||||
| <text  x="1125.40" y="95.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>___pthread_cond_clockwait64 (256 samples, 66.67%)</title><rect x="132.9" y="245" width="786.7" height="15.0" fill="rgb(233,129,30)" rx="2" ry="2" /> | ||||
| <text  x="135.92" y="255.5" >___pthread_cond_clockwait64</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>operator() (9 samples, 2.34%)</title><rect x="1054.8" y="197" width="27.6" height="15.0" fill="rgb(231,121,29)" rx="2" ry="2" /> | ||||
| <text  x="1057.79" y="207.5" >o..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__GI___clock_nanosleep (1 samples, 0.26%)</title><rect x="120.6" y="213" width="3.1" height="15.0" fill="rgb(232,126,30)" rx="2" ry="2" /> | ||||
| <text  x="123.62" y="223.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__futex_abstimed_wait_common (13 samples, 3.39%)</title><rect x="1082.4" y="117" width="40.0" height="15.0" fill="rgb(205,0,0)" rx="2" ry="2" /> | ||||
| <text  x="1085.45" y="127.5" >__f..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__GI___poll (4 samples, 1.04%)</title><rect x="919.6" y="197" width="12.3" height="15.0" fill="rgb(228,110,26)" rx="2" ry="2" /> | ||||
| <text  x="922.58" y="207.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__pthread_cond_wait_common (20 samples, 5.21%)</title><rect x="1128.5" y="261" width="61.5" height="15.0" fill="rgb(210,24,5)" rx="2" ry="2" /> | ||||
| <text  x="1131.54" y="271.5" >__pthr..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>nlohmann::json_abi_v3_11_2::detail::lexer<nlohmann::json_abi_v3_11_2::basic_json<std::map, (1 samples, 0.26%)</title><rect x="1079.4" y="85" width="3.0" height="15.0" fill="rgb(222,78,18)" rx="2" ry="2" /> | ||||
| <text  x="1082.38" y="95.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>nlohmann::json_abi_v3_11_2::detail::parser<nlohmann::json_abi_v3_11_2::basic_json<std::map, (1 samples, 0.26%)</title><rect x="1079.4" y="133" width="3.0" height="15.0" fill="rgb(217,59,14)" rx="2" ry="2" /> | ||||
| <text  x="1082.38" y="143.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>dpp::discord_voice_client::thread_run() (20 samples, 5.21%)</title><rect x="71.5" y="277" width="61.4" height="15.0" fill="rgb(238,153,36)" rx="2" ry="2" /> | ||||
| <text  x="74.46" y="287.5" >dpp::d..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>dpp::discord_client::thread_run() (20 samples, 5.21%)</title><rect x="10.0" y="277" width="61.5" height="15.0" fill="rgb(251,214,51)" rx="2" ry="2" /> | ||||
| <text  x="13.00" y="287.5" >dpp::d..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>nlohmann::json_abi_v3_11_2::detail::lexer<nlohmann::json_abi_v3_11_2::basic_json<std::map, (1 samples, 0.26%)</title><rect x="1079.4" y="101" width="3.0" height="15.0" fill="rgb(222,78,18)" rx="2" ry="2" /> | ||||
| <text  x="1082.38" y="111.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__GI___poll (15 samples, 3.91%)</title><rect x="71.5" y="245" width="46.1" height="15.0" fill="rgb(228,110,26)" rx="2" ry="2" /> | ||||
| <text  x="74.46" y="255.5" >__GI..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__GI___underflow (3 samples, 0.78%)</title><rect x="1057.9" y="133" width="9.2" height="15.0" fill="rgb(221,74,17)" rx="2" ry="2" /> | ||||
| <text  x="1060.86" y="143.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>std::thread::_State_impl<std::thread::_Invoker<std::tuple<bumbleBee::BumbleBee::on_slashcommand(const (9 samples, 2.34%)</title><rect x="1054.8" y="277" width="27.6" height="15.0" fill="rgb(249,203,48)" rx="2" ry="2" /> | ||||
| <text  x="1057.79" y="287.5" >s..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__GI___futex_abstimed_wait_cancelable64 (13 samples, 3.39%)</title><rect x="1082.4" y="133" width="40.0" height="15.0" fill="rgb(215,48,11)" rx="2" ry="2" /> | ||||
| <text  x="1085.45" y="143.5" >__G..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>___pthread_cond_clockwait64 (256 samples, 66.67%)</title><rect x="132.9" y="261" width="786.7" height="15.0" fill="rgb(233,129,30)" rx="2" ry="2" /> | ||||
| <text  x="135.92" y="271.5" >___pthread_cond_clockwait64</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>dpp::https_client::https_client(std::__cxx11::basic_string<char, (4 samples, 1.04%)</title><rect x="919.6" y="245" width="12.3" height="15.0" fill="rgb(206,4,1)" rx="2" ry="2" /> | ||||
| <text  x="922.58" y="255.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>nlohmann::json_abi_v3_11_2::detail::lexer<nlohmann::json_abi_v3_11_2::basic_json<std::map, (1 samples, 0.26%)</title><rect x="1079.4" y="69" width="3.0" height="15.0" fill="rgb(222,78,18)" rx="2" ry="2" /> | ||||
| <text  x="1082.38" y="79.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>dpp::ssl_client::read_loop() (20 samples, 5.21%)</title><rect x="71.5" y="261" width="61.4" height="15.0" fill="rgb(243,175,41)" rx="2" ry="2" /> | ||||
| <text  x="74.46" y="271.5" >dpp::s..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__GI___futex_abstimed_wait_cancelable64 (40 samples, 10.42%)</title><rect x="931.9" y="213" width="122.9" height="15.0" fill="rgb(215,48,11)" rx="2" ry="2" /> | ||||
| <text  x="934.88" y="223.5" >__GI___futex_ab..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__futex_abstimed_wait_common64 (40 samples, 10.42%)</title><rect x="931.9" y="181" width="122.9" height="15.0" fill="rgb(220,71,17)" rx="2" ry="2" /> | ||||
| <text  x="934.88" y="191.5" >__futex_abstime..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>futex_wait (1 samples, 0.26%)</title><rect x="117.6" y="181" width="3.0" height="15.0" fill="rgb(235,138,33)" rx="2" ry="2" /> | ||||
| <text  x="120.55" y="191.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__pthread_cond_wait_common (256 samples, 66.67%)</title><rect x="132.9" y="229" width="786.7" height="15.0" fill="rgb(210,24,5)" rx="2" ry="2" /> | ||||
| <text  x="135.92" y="239.5" >__pthread_cond_wait_common</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>std::vector<char, (1 samples, 0.26%)</title><rect x="1079.4" y="53" width="3.0" height="15.0" fill="rgb(222,81,19)" rx="2" ry="2" /> | ||||
| <text  x="1082.38" y="63.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>std::condition_variable::wait<bumbleBee::MusicPlayManager::play(dpp::discord_voice_client*)::<lambda(dpp::discord_voice_client*)>::<lambda()> (13 samples, 3.39%)</title><rect x="1082.4" y="181" width="40.0" height="15.0" fill="rgb(242,172,41)" rx="2" ry="2" /> | ||||
| <text  x="1085.45" y="191.5" >std..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__GI___libc_read (3 samples, 0.78%)</title><rect x="1057.9" y="85" width="9.2" height="15.0" fill="rgb(241,166,39)" rx="2" ry="2" /> | ||||
| <text  x="1060.86" y="95.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__GI__IO_fread (2 samples, 0.52%)</title><rect x="1122.4" y="149" width="6.1" height="15.0" fill="rgb(212,34,8)" rx="2" ry="2" /> | ||||
| <text  x="1125.40" y="159.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>?? (364 samples, 94.79%)</title><rect x="10.0" y="293" width="1118.5" height="15.0" fill="rgb(249,205,49)" rx="2" ry="2" /> | ||||
| <text  x="13.00" y="303.5" >??</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__futex_abstimed_wait_common (20 samples, 5.21%)</title><rect x="1128.5" y="229" width="61.5" height="15.0" fill="rgb(205,0,0)" rx="2" ry="2" /> | ||||
| <text  x="1131.54" y="239.5" >__fute..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>start_thread (364 samples, 94.79%)</title><rect x="10.0" y="309" width="1118.5" height="15.0" fill="rgb(212,34,8)" rx="2" ry="2" /> | ||||
| <text  x="13.00" y="319.5" >start_thread</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__GI___lll_lock_wait (1 samples, 0.26%)</title><rect x="117.6" y="197" width="3.0" height="15.0" fill="rgb(226,96,23)" rx="2" ry="2" /> | ||||
| <text  x="120.55" y="207.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>clone3 (364 samples, 94.79%)</title><rect x="10.0" y="325" width="1118.5" height="15.0" fill="rgb(216,54,12)" rx="2" ry="2" /> | ||||
| <text  x="13.00" y="335.5" >clone3</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>dpp::http_request::run(dpp::cluster*) (4 samples, 1.04%)</title><rect x="919.6" y="261" width="12.3" height="15.0" fill="rgb(230,119,28)" rx="2" ry="2" /> | ||||
| <text  x="922.58" y="271.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__GI__IO_default_uflow (4 samples, 1.04%)</title><rect x="1067.1" y="101" width="12.3" height="15.0" fill="rgb(234,135,32)" rx="2" ry="2" /> | ||||
| <text  x="1070.08" y="111.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>std::thread::_Invoker<std::tuple<bumbleBee::MusicPlayManager::play(dpp::discord_voice_client*)::<lambda(dpp::discord_voice_client*)>, (13 samples, 3.39%)</title><rect x="1082.4" y="245" width="40.0" height="15.0" fill="rgb(208,13,3)" rx="2" ry="2" /> | ||||
| <text  x="1085.45" y="255.5" >std..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__GI___libc_read (4 samples, 1.04%)</title><rect x="1067.1" y="69" width="12.3" height="15.0" fill="rgb(241,166,39)" rx="2" ry="2" /> | ||||
| <text  x="1070.08" y="79.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__GI___libc_read (3 samples, 0.78%)</title><rect x="1057.9" y="101" width="9.2" height="15.0" fill="rgb(241,166,39)" rx="2" ry="2" /> | ||||
| <text  x="1060.86" y="111.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>_IO_new_file_underflow (4 samples, 1.04%)</title><rect x="1067.1" y="85" width="12.3" height="15.0" fill="rgb(214,42,10)" rx="2" ry="2" /> | ||||
| <text  x="1070.08" y="95.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__GI___libc_read (4 samples, 1.04%)</title><rect x="1067.1" y="53" width="12.3" height="15.0" fill="rgb(241,166,39)" rx="2" ry="2" /> | ||||
| <text  x="1070.08" y="63.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>dpp::discord_voice_client::stop_audio() (1 samples, 0.26%)</title><rect x="1054.8" y="149" width="3.1" height="15.0" fill="rgb(217,57,13)" rx="2" ry="2" /> | ||||
| <text  x="1057.79" y="159.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>std::__invoke<bumbleBee::BumbleBee::on_slashcommand(const (9 samples, 2.34%)</title><rect x="1054.8" y="229" width="27.6" height="15.0" fill="rgb(253,222,53)" rx="2" ry="2" /> | ||||
| <text  x="1057.79" y="239.5" >s..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>dpp::ssl_client::read_loop() (20 samples, 5.21%)</title><rect x="10.0" y="261" width="61.5" height="15.0" fill="rgb(243,175,41)" rx="2" ry="2" /> | ||||
| <text  x="13.00" y="271.5" >dpp::s..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__GI__IO_getline_info (4 samples, 1.04%)</title><rect x="1067.1" y="117" width="12.3" height="15.0" fill="rgb(248,199,47)" rx="2" ry="2" /> | ||||
| <text  x="1070.08" y="127.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>bumbleBee::commands::Delete::execute (1 samples, 0.26%)</title><rect x="1054.8" y="181" width="3.1" height="15.0" fill="rgb(246,190,45)" rx="2" ry="2" /> | ||||
| <text  x="1057.79" y="191.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>std::__invoke_impl<void, (2 samples, 0.52%)</title><rect x="1122.4" y="213" width="6.1" height="15.0" fill="rgb(244,179,42)" rx="2" ry="2" /> | ||||
| <text  x="1125.40" y="223.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>dpp::cluster::start(bool) (20 samples, 5.21%)</title><rect x="1128.5" y="293" width="61.5" height="15.0" fill="rgb(205,0,0)" rx="2" ry="2" /> | ||||
| <text  x="1131.54" y="303.5" >dpp::c..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>std::vector<dpp::voice_out_packet, (3 samples, 0.78%)</title><rect x="123.7" y="229" width="9.2" height="15.0" fill="rgb(222,82,19)" rx="2" ry="2" /> | ||||
| <text  x="126.70" y="239.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>dpp::discord_voice_client::want_write() (1 samples, 0.26%)</title><rect x="117.6" y="245" width="3.0" height="15.0" fill="rgb(233,130,31)" rx="2" ry="2" /> | ||||
| <text  x="120.55" y="255.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__pthread_cond_wait_common (13 samples, 3.39%)</title><rect x="1082.4" y="149" width="40.0" height="15.0" fill="rgb(210,24,5)" rx="2" ry="2" /> | ||||
| <text  x="1085.45" y="159.5" >__p..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__futex_abstimed_wait_common64 (256 samples, 66.67%)</title><rect x="132.9" y="181" width="786.7" height="15.0" fill="rgb(220,71,17)" rx="2" ry="2" /> | ||||
| <text  x="135.92" y="191.5" >__futex_abstimed_wait_common64</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__GI___nanosleep (1 samples, 0.26%)</title><rect x="120.6" y="229" width="3.1" height="15.0" fill="rgb(231,119,28)" rx="2" ry="2" /> | ||||
| <text  x="123.62" y="239.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>oggz_read (2 samples, 0.52%)</title><rect x="1122.4" y="181" width="6.1" height="15.0" fill="rgb(252,218,52)" rx="2" ry="2" /> | ||||
| <text  x="1125.40" y="191.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>operator() (13 samples, 3.39%)</title><rect x="1082.4" y="197" width="40.0" height="15.0" fill="rgb(231,121,29)" rx="2" ry="2" /> | ||||
| <text  x="1085.45" y="207.5" >ope..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>std::thread::_Invoker<std::tuple<bumbleBee::MusicPlayManager::send_audio_to_voice(std::shared_ptr<bumbleBee::MusicQueueElement>, (2 samples, 0.52%)</title><rect x="1122.4" y="261" width="6.1" height="15.0" fill="rgb(216,50,12)" rx="2" ry="2" /> | ||||
| <text  x="1125.40" y="271.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__GI___futex_abstimed_wait_cancelable64 (256 samples, 66.67%)</title><rect x="132.9" y="213" width="786.7" height="15.0" fill="rgb(215,48,11)" rx="2" ry="2" /> | ||||
| <text  x="135.92" y="223.5" >__GI___futex_abstimed_wait_cancelable64</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>nlohmann::json_abi_v3_11_2::detail::parser<nlohmann::json_abi_v3_11_2::basic_json<std::map, (1 samples, 0.26%)</title><rect x="1079.4" y="117" width="3.0" height="15.0" fill="rgb(217,59,14)" rx="2" ry="2" /> | ||||
| <text  x="1082.38" y="127.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>std::move<char&> (1 samples, 0.26%)</title><rect x="1079.4" y="37" width="3.0" height="15.0" fill="rgb(232,124,29)" rx="2" ry="2" /> | ||||
| <text  x="1082.38" y="47.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>bumbleBee::ConsoleUtils::getResultFromCommand (4 samples, 1.04%)</title><rect x="1067.1" y="165" width="12.3" height="15.0" fill="rgb(223,85,20)" rx="2" ry="2" /> | ||||
| <text  x="1070.08" y="175.5" ></text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__futex_abstimed_wait_common64 (20 samples, 5.21%)</title><rect x="1128.5" y="213" width="61.5" height="15.0" fill="rgb(220,71,17)" rx="2" ry="2" /> | ||||
| <text  x="1131.54" y="223.5" >__fute..</text> | ||||
| </g> | ||||
| <g > | ||||
| <title>__GI___futex_abstimed_wait_cancelable64 (20 samples, 5.21%)</title><rect x="1128.5" y="245" width="61.5" height="15.0" fill="rgb(215,48,11)" rx="2" ry="2" /> | ||||
| <text  x="1131.54" y="255.5" >__GI__..</text> | ||||
| </g> | ||||
| </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 36 KiB | 
							
								
								
									
										4
									
								
								systemStackCapture.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										4
									
								
								systemStackCapture.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| sudo echo recording... | ||||
| sudo perf record -F 99 -a -g -- sleep 60 | ||||
| sudo perf script | ./stackcollapse-perf.pl | ./flamegraph.pl > stackflame.svg | ||||
| sudo rm perf.data | ||||
		Reference in New Issue
	
	Block a user