* Copyright (C) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include "test-malloc-info-stats-print.h"
#include "libxml/parser.h"
static const xmlChar *get_text_from_children(xmlNodePtr children)
{
for (xmlNodePtr child_node = children; child_node != NULL; child_node = child_node->next) {
if (child_node->type == XML_TEXT_NODE) {
return child_node->content;
}
}
return NULL;
}
static const xmlChar *get_attribute(const char *attr_name, xmlNodePtr node)
{
for (xmlAttrPtr curr_attr = node->properties; curr_attr != NULL; curr_attr = curr_attr->next) {
if (xmlStrEqual(curr_attr->name, (const xmlChar *) attr_name)) {
return get_text_from_children(curr_attr->children);
}
}
return NULL;
}
static xmlNodePtr find_child_node_with_attr(const char *name, const char *attr_name, const char *attr_value, xmlNodePtr parent)
{
if (parent == NULL) {
return NULL;
}
for (xmlNodePtr curr_node = parent->children; curr_node != NULL; curr_node = curr_node->next) {
if (curr_node->type == XML_ELEMENT_NODE && xmlStrEqual(curr_node->name, (xmlChar *) name)) {
if (attr_name == NULL) {
return curr_node;
}
if (xmlStrEqual(get_attribute(attr_name, curr_node), (const xmlChar *) attr_value)) {
return curr_node;
}
}
}
return NULL;
}
static xmlNodePtr find_child_node(const char *name, xmlNodePtr parent)
{
return find_child_node_with_attr(name, NULL, NULL, parent);
}
static const char *get_node_text(xmlNodePtr node_ptr)
{
if (node_ptr == NULL) {
return NULL;
}
return (const char *) get_text_from_children(node_ptr->children);
}
static void stderr_stats_cb(void)
{
malloc_info(0, stderr);
}
static long long parse_amount(const char *s)
{
if (s == NULL) {
return -1;
}
char *end_ptr;
long long result = strtoll(s, &end_ptr, 10);
if (end_ptr != s + strlen(s)) {
return -1;
}
if (result < 0) {
return -1;
}
return result;
}
static xmlNodePtr find_thread_in_document(xmlDocPtr doc_ptr, const char *thread_id)
{
xmlNodePtr root_element = xmlDocGetRootElement(doc_ptr);
return find_child_node_with_attr("thread", "id", thread_id, find_child_node("threads", root_element));
}
static int populate_thread_stats(const char *output, const char *thread_id, malloc_thread_stats_t *stats)
{
xmlDocPtr doc_ptr = xmlParseDoc((const xmlChar *) output);
if (doc_ptr == NULL) {
return 0;
}
xmlNodePtr thread_root = find_thread_in_document(doc_ptr, thread_id);
long long total_allocated_memory =
parse_amount(get_node_text(find_child_node("total_allocated_memory", thread_root)));
long long total_mmapped_memory =
parse_amount(get_node_text(find_child_node("total_mmapped_memory", thread_root)));
long long mmapped_regions =
parse_amount(get_node_text(find_child_node("mmapped_regions", thread_root)));
xmlFreeDoc(doc_ptr);
if (total_allocated_memory == -1 || total_mmapped_memory == -1 || mmapped_regions == -1) {
return 0;
}
stats->total_allocated_memory = total_allocated_memory;
stats->total_mmapped_memory = total_mmapped_memory;
stats->mmapped_regions = mmapped_regions;
return 1;
}
static int populate_total_free_heap_space(const char *output, long long *total_free_heap_space)
{
xmlDocPtr doc_ptr = xmlParseDoc((const xmlChar *) output);
if (doc_ptr == NULL) {
return 0;
}
xmlNodePtr heap_space_root = find_child_node("total_free_heap_space", xmlDocGetRootElement(doc_ptr));
long long total_free_heap_space_parsed = parse_amount(get_node_text(heap_space_root));
xmlFreeDoc(doc_ptr);
if (total_free_heap_space_parsed == -1) {
return 0;
}
*total_free_heap_space = total_free_heap_space_parsed;
return 1;
}
static int is_thread_in_output(const char *output, const char *thread_id)
{
xmlDocPtr doc_ptr = xmlParseDoc((const xmlChar *) output);
if (doc_ptr == NULL) {
return 0;
}
int result = find_thread_in_document(doc_ptr, thread_id) != NULL;
xmlFreeDoc(doc_ptr);
return result;
}