diff --git a/src/Makefile_Evas.am b/src/Makefile_Evas.am index de3636bf7d..7a52016126 100644 --- a/src/Makefile_Evas.am +++ b/src/Makefile_Evas.am @@ -999,7 +999,8 @@ bin/evas/dummy_slave bin_PROGRAMS += \ bin/evas/evas_cserve2_client \ bin/evas/evas_cserve2_usage \ -bin/evas/evas_cserve2_debug +bin/evas/evas_cserve2_debug \ +bin/evas/evas_cserve2_shm_debug bin_evas_evas_cserve2_SOURCES = \ bin/evas/evas_cserve2.h \ @@ -1056,6 +1057,15 @@ bin_evas_evas_cserve2_debug_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ bin_evas_evas_cserve2_debug_LDADD = @USE_EINA_LIBS@ bin_evas_evas_cserve2_debug_DEPENDENCIES = @USE_EINA_INTERNAL_LIBS@ +bin_evas_evas_cserve2_shm_debug_SOURCES = \ +bin/evas/evas_cserve2_shm_debug.c +bin_evas_evas_cserve2_shm_debug_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ +-I$(top_srcdir)/src/lib/evas \ +-I$(top_srcdir)/src/lib/evas/cserve2 \ +@EINA_CFLAGS@ +bin_evas_evas_cserve2_shm_debug_LDADD = @USE_EINA_LIBS@ +bin_evas_evas_cserve2_shm_debug_DEPENDENCIES = @USE_EINA_INTERNAL_LIBS@ + bin_evas_evas_cserve2_slave_SOURCES = \ bin/evas/evas_cserve2_slave.c \ bin/evas/evas_cserve2_utils.c \ diff --git a/src/bin/evas/evas_cserve2_shm_debug.c b/src/bin/evas/evas_cserve2_shm_debug.c new file mode 100644 index 0000000000..e17e5d2b40 --- /dev/null +++ b/src/bin/evas/evas_cserve2_shm_debug.c @@ -0,0 +1,759 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include "evas_cs2.h" + +#define SHM_FOLDER "/dev/shm" +static int _evas_cserve2_shm_debug_log_dom = -1; + +#define ERR(...) EINA_LOG_DOM_ERR(_evas_cserve2_shm_debug_log_dom, __VA_ARGS__) +#define DBG(...) EINA_LOG_DOM_DBG(_evas_cserve2_shm_debug_log_dom, __VA_ARGS__) +#define WRN(...) EINA_LOG_DOM_WARN(_evas_cserve2_shm_debug_log_dom, __VA_ARGS__) +#define INF(...) EINA_LOG_DOM_INFO(_evas_cserve2_shm_debug_log_dom, __VA_ARGS__) + +typedef struct _Shm_File Shm_File; +struct _Shm_File +{ + Eina_File *f; + char *data; + size_t size; + int tag; + + Eina_Bool strings; + Shared_Array_Header *header; +}; + +Shm_File *sf_strindex = NULL; +Shm_File *sf_strpool = NULL; +Shm_File *sf_fonts = NULL; +Shm_File *sf_files = NULL; +Shm_File *sf_images = NULL; + +static int _termsize = 0; + +static void +nprintf(int n, const char *fmt, ...) +{ + char buf[n+1]; + va_list arg; + int len; + + va_start(arg, fmt); + if (!n) + vprintf(fmt, arg); + else + { + len = vsnprintf(buf, n+1, fmt, arg); + buf[n] = 0; + fputs(buf, stdout); + if ((len > 0) && (buf[len-1] != '\n')) + fputc('\n', stdout); + } + va_end(arg); +} + +#define printf(...) nprintf(_termsize, __VA_ARGS__) + +static Shm_File * +_shm_file_open(const char *path) +{ + Shm_File *sf; + Eina_File *f; + char *data; + + f = eina_file_open(path, EINA_TRUE); + if (!f) + { + ERR("Could not open file %s: [%d] %m", path, errno); + return NULL; + } + + data = eina_file_map_all(f, EINA_FILE_RANDOM); + if (!data) + { + ERR("Could not map the file %s", path); + eina_file_close(f); + return NULL; + } + + sf = calloc(1, sizeof(*sf)); + sf->data = data; + sf->f = f; + sf->size = eina_file_size_get(f); + + DBG("Successfully opened %s", path); + return sf; +} + +static void +_shm_file_close(Shm_File *sf) +{ + if (!sf) return; + eina_file_map_free(sf->f, sf->data); + eina_file_close(sf->f); + free(sf); +} + +static Eina_Bool +_shm_file_probe(Shm_File *sf) +{ + if (!sf || !sf->data) + return EINA_FALSE; + + if (sf->size < sizeof(Shared_Array_Header)) + { + sf->header = NULL; + return EINA_TRUE; + } + + sf->header = (Shared_Array_Header *) sf->data; + switch (sf->header->tag) + { + case STRING_INDEX_ARRAY_TAG: + DBG("Found string index: %s", eina_file_filename_get(sf->f)); + if (sf->header->elemsize != sizeof(Index_Entry)) + { + ERR("String index looks invalid: elemsize %d", + sf->header->elemsize); + return EINA_FALSE; + } + sf->tag = STRING_INDEX_ARRAY_TAG; + sf_strindex = sf; + break; + + case STRING_MEMPOOL_FAKETAG: + DBG("Found string mempool: %s", eina_file_filename_get(sf->f)); + sf->strings = EINA_TRUE; + sf->tag = STRING_MEMPOOL_FAKETAG; + sf->header = NULL; + sf_strpool = sf; + break; + + case FILE_DATA_ARRAY_TAG: + DBG("Found index table with tag '%4.4s'", (char *) &sf->header->tag); + sf->tag = sf->header->tag; + sf_files = sf; + break; + + case IMAGE_DATA_ARRAY_TAG: + DBG("Found index table with tag '%4.4s'", (char *) &sf->header->tag); + sf->tag = sf->header->tag; + sf_images = sf; + break; + + case FONT_DATA_ARRAY_TAG: + DBG("Found index table with tag '%4.4s'", (char *) &sf->header->tag); + sf->tag = sf->header->tag; + sf_fonts = sf; + break; + + case GLYPH_INDEX_ARRAY_TAG: + DBG("Found index table with tag '%4.4s'", (char *) &sf->header->tag); + sf->tag = sf->header->tag; + break; + + case GLYPH_DATA_ARRAY_TAG: + DBG("Found index table with tag '%4.4s'", (char *) &sf->header->tag); + sf->tag = sf->header->tag; + break; + + default: + //DBG("Unknown tag found: %d", sf->header->tag); + sf->header = NULL; + break; + } + + return EINA_TRUE; +} + +static Eina_List * +_shm_files_list(const char *folder) +{ + Eina_List *lst = NULL; + Eina_Iterator *iter; + const Eina_File_Direct_Info *f_info; + char pattern[64]; + + sprintf(pattern, "/evas-shm-%x-", (int) getuid()); + iter = eina_file_direct_ls(folder); + EINA_ITERATOR_FOREACH(iter, f_info) + { + if (strstr(f_info->path, pattern)) + { + const char *shmname = strrchr(f_info->path, '/'); + if (!shmname) continue; + + lst = eina_list_append(lst, strdup(shmname)); + } + else + DBG("cserve2 cleanup: ignoring %s", f_info->path); + } + eina_iterator_free(iter); + + return lst; +} + +static void +printf_newline(Eina_Bool flush) +{ + printf("----------------------------------------------------------------" + "----------------\n"); + + if (flush) + { + printf("\n\n"); + fflush(stdout); + } +} + +static void +_index_tables_summary_print(void) +{ + printf("Shared index tables\n\n"); + printf("Table Tag MapSize Gen ElSz Count Last Sort Path\n"); + printf_newline(0); + + printf("StrIdx %4.4s %7d %4d %4d %5d %5d %5d %s\n", + (char *) &sf_strindex->tag, + (int) eina_file_size_get(sf_strindex->f), + sf_strindex->header->generation_id, sf_strindex->header->elemsize, + sf_strindex->header->count, sf_strindex->header->emptyidx, + sf_strindex->header->sortedidx, + eina_file_filename_get(sf_strindex->f)); + + printf("StrData %4.4s %7d %s\n", + (char *) &sf_strpool->tag, + (int) eina_file_size_get(sf_strpool->f), + eina_file_filename_get(sf_strpool->f)); + + if (sf_files) + printf("FileIdx %4.4s %7d %4d %4d %5d %5d %5d %s\n", + (char *) &sf_files->tag, + (int) eina_file_size_get(sf_files->f), + sf_files->header->generation_id, sf_files->header->elemsize, + sf_files->header->count, sf_files->header->emptyidx, + sf_files->header->sortedidx, + eina_file_filename_get(sf_files->f)); + else + printf("FileIdx \n"); + + if (sf_images) + printf("Images %4.4s %7d %4d %4d %5d %5d %5d %s\n", + (char *) &sf_images->tag, + (int) eina_file_size_get(sf_images->f), + sf_images->header->generation_id, sf_images->header->elemsize, + sf_images->header->count, sf_images->header->emptyidx, + sf_images->header->sortedidx, + eina_file_filename_get(sf_images->f)); + else + printf("Images \n"); + + if (sf_fonts) + printf("FontIdx %4.4s %7d %4d %4d %5d %5d %5d %s\n", + (char *) &sf_fonts->tag, + (int) eina_file_size_get(sf_fonts->f), + sf_fonts->header->generation_id, sf_fonts->header->elemsize, + sf_fonts->header->count, sf_fonts->header->emptyidx, + sf_fonts->header->sortedidx, + eina_file_filename_get(sf_fonts->f)); + else + printf("FontIdx \n"); + + printf_newline(1); +} + +static const Shm_Object * +_shared_index_item_get_by_id(Shm_File *si, int elemsize, unsigned int id) +{ + const Shm_Object *obj; + const char *base; + int low = 0, high, start_high; + int cur; + + if (!si || elemsize <= 0 || !id) + return NULL; + + // FIXME: HACK (consider all arrays always sorted by id) + high = si->header->emptyidx; // Should be si->header->sortedidx + + if (high > si->header->count) + high = si->header->count; + + base = si->data + sizeof(Shared_Array_Header); + + // Binary search + start_high = high; + while(high != low) + { + cur = low + ((high - low) / 2); + obj = (Shm_Object *) (base + (elemsize * cur)); + if (obj->id == id) + return obj; + if (obj->id < id) + low = cur + 1; + else + high = cur; + } + + // Linear search + for (cur = start_high; cur < si->header->count; cur++) + { + obj = (Shm_Object *) (base + (elemsize * cur)); + if (!obj->id) + return NULL; + if (obj->id == id) + return obj; + } + + return NULL; +} + +static void * +_shared_array_item_get(Shm_File *sf, int idx) +{ + if (!sf || !sf->header || idx < 0) + return NULL; + + if ((idx + 1) * sf->header->elemsize > (int) sf->size) + return NULL; + + return (sf->data + sizeof(Shared_Array_Header) + idx * sf->header->elemsize); +} + +static const char * +_shared_string_get(int id) +{ + Index_Entry *ie; + + ie = (Index_Entry *) + _shared_index_item_get_by_id(sf_strindex, sizeof(*ie), id); + if (!ie) return NULL; + if (ie->offset < 0) return NULL; + if (!ie->refcount) return NULL; + if (ie->offset + ie->length > (int) sf_strpool->size) return NULL; + + return sf_strpool->data + ie->offset; +} + +static void +_strings_all_print(Eina_Bool full) +{ + int k; + const char *mindata = sf_strpool->data; + const char *maxdata = sf_strpool->data + sf_strpool->size; + + printf("List of strings\n"); + printf("Indexes: %s\n", eina_file_filename_get(sf_strindex->f)); + printf("Data: %s\n", eina_file_filename_get(sf_strpool->f)); + printf(" String BufID Refcnt Offset Buflen Content\n"); + printf_newline(0); + + for (k = 0; k < sf_strindex->header->count; k++) + { + Index_Entry *ie; + const char *data; + + ie = _shared_array_item_get(sf_strindex, k); + if (!ie) break; + + if (!ie->id || (!full && !ie->refcount)) + continue; + + data = sf_strpool->data + ie->offset; + if ((data < mindata) || (data + ie->length > maxdata)) + data = ""; + + printf("%7d %7d %7d %7d %7d '%s'\n", + k, ie->id, ie->refcount, ie->offset, ie->length, data); + } + + printf_newline(1); +} + +static void +_files_all_print(Eina_Bool full) +{ + int k; + + if (!sf_files) return; + + printf("List of image files: %s\n", eina_file_filename_get(sf_files->f)); + printf("A: Alpha, I: Invalid.\n\n"); + printf(" Index FileID WIDTHxHEIGHT A I Loader PathID KeyID Path:Key\n"); + printf_newline(0); + + for (k = 0; k < sf_files->header->count; k++) + { + File_Data *fd; + + fd = _shared_array_item_get(sf_files, k); + if (!fd) break; + if (!fd->id || (!full && !fd->refcount)) continue; + + printf("%7d %7d %5dx%-6d %d %d %6.6s %6d %6d '%s':'%s'\n", + k, fd->id, fd->w, fd->h, !!fd->alpha, !!fd->invalid, + fd->loader_data ? _shared_string_get(fd->loader_data) : "", + fd->path, fd->key, _shared_string_get(fd->path), + _shared_string_get(fd->key)); + } + + printf_newline(1); +} + +static void +_images_all_print_short(void) +{ + int k; + + if (!sf_images) return; + + printf("List of loaded images: %s\n", eina_file_filename_get(sf_images->f)); + printf("A: Sparse alpha, U: Unused, L: Load requested.\n\n"); + printf(" Index ImageID FileID Refcnt A U L ShmID ShmPath\n"); + printf_newline(0); + + for (k = 0; k < sf_images->header->count; k++) + { + Image_Data *id; + + id = _shared_array_item_get(sf_images, k); + if (!id) break; + if (!id->id || !id->refcount) continue; + + printf("%7d %7d %7d %7d %d %d %d %7d '%s'\n", + k, id->id, id->file_id, id->refcount, + !!id->alpha_sparse, !!id->unused, !!id->doload, id->shm_id, + id->shm_id ? _shared_string_get(id->shm_id) : ""); + } + + printf_newline(1); +} + +static void +_images_all_print_full(void) +{ + int k; + + if (!sf_images) return; + + printf("List of loaded images: %s\n\n", + eina_file_filename_get(sf_images->f)); + printf_newline(0); + + for (k = 0; k < sf_images->header->count; k++) + { + Image_Data *id; + File_Data *fd; + const char *scale_hint; + + id = _shared_array_item_get(sf_images, k); + if (!id) break; + if (!id->id) continue; + + printf("Image #%-8d %d\n", k, id->id); + printf("Refcount %d\n", id->refcount); + printf("Sparse alpha %s\n" + "Unused: %s\n" + "Load requested: %s\n", + id->alpha_sparse ? "YES" : "NO", + id->unused ? "YES" : "NO", + id->doload ? "YES" : "NO"); + printf("Shm Path: '%s'\n", + id->shm_id ? _shared_string_get(id->shm_id) : ""); + + printf("LoadOpts: width %d\n", id->opts.w); + printf(" height %d\n", id->opts.h); + printf(" degree %d\n", id->opts.degree); + printf(" scale_down_by %d\n", id->opts.scale_down_by); + if (id->opts.dpi) + printf(" dpi %.2f\n", id->opts.dpi); + else + printf(" dpi 0\n"); + printf(" orientation %s\n", id->opts.orientation ? "YES" : "NO"); + printf(" region (%d,%d) %dx%d\n", + id->opts.region.x, id->opts.region.y, + id->opts.region.w, id->opts.region.h); + + switch (id->opts.scale_load.scale_hint) + { + case EVAS_IMAGE_SCALE_HINT_NONE: + scale_hint = "EVAS_IMAGE_SCALE_HINT_NONE"; break; + case EVAS_IMAGE_SCALE_HINT_DYNAMIC: + scale_hint = "EVAS_IMAGE_SCALE_HINT_DYNAMIC"; break; + case EVAS_IMAGE_SCALE_HINT_STATIC: + scale_hint = "EVAS_IMAGE_SCALE_HINT_STATIC"; break; + default: + scale_hint = ""; break; + } + + printf(" scale src (%d,%d) %dx%d\n", + id->opts.scale_load.src_x, id->opts.scale_load.src_y, + id->opts.scale_load.src_w, id->opts.scale_load.src_h); + printf(" scale dst %dx%d\n", + id->opts.scale_load.dst_w, id->opts.scale_load.dst_h); + printf(" scale smooth %s\n", + id->opts.scale_load.smooth ? "YES" : "NO"); + printf(" scale hint %s (%d)\n", + scale_hint, id->opts.scale_load.scale_hint); + + fd = (File_Data *) + _shared_index_item_get_by_id(sf_files, sizeof(*fd), id->file_id); + if (fd) + { + printf("File: ID %d\n", id->file_id); + printf(" Path:Key: '%s':'%s'\n", + _shared_string_get(fd->path), _shared_string_get(fd->key)); + printf(" Loader: %s\n", + _shared_string_get(fd->loader_data)); + printf(" Geometry: %dx%d\n", fd->w, fd->h); + printf(" Animation: frames: %d, loop: %d, hint: %d\n", + fd->frame_count, fd->loop_count, fd->loop_hint); + printf(" Alpha: %s\n", fd->alpha ? "YES" : "NO"); + printf(" Invalid: %s\n", fd->invalid ? "YES" : "NO"); + } + else + printf("File: ID %d not found\n", id->file_id); + + printf_newline(0); + } + + printf("\n\n"); + fflush(stdout); +} + +static void +_fonts_all_print_short(void) +{ + int k; + + static const char *rend_flags[] = { "R", "S", "W", "SW", "X" }; + + if (!sf_fonts) return; + + printf("List of loaded fonts: %s\n", eina_file_filename_get(sf_fonts->f)); + printf("Rendering flags (RF): " + "R: Regular, S: Slanted, W: Weight, X: Invalid\n\n"); + printf(" Index FontID Refcnt Size DPI RF GlIdx GlData File[:Name]\n"); + printf_newline(0); + + for (k = 0; k < sf_fonts->header->count; k++) + { + Font_Data *fd; + int rflag; + const char *rf; + + fd = _shared_array_item_get(sf_fonts, k); + if (!fd) break; + if (!fd->id || !fd->refcount) continue; + + rflag = fd->rend_flags; + if (rflag < 0 || rflag > 3) rflag = 4; + rf = rend_flags[rflag]; + + if (fd->name) + printf("%6d %6d %6d %5d %5d %-2s %6d %6d '%s':'%s'\n", + k, fd->id, fd->refcount, fd->size, fd->dpi, rf, + fd->glyph_index_shm, fd->mempool_shm, + fd->file ? _shared_string_get(fd->file) : "", + _shared_string_get(fd->name)); + else + printf("%6d %6d %6d %5d %5d %-2s %6d %6d '%s'\n", + k, fd->id, fd->refcount, fd->size, fd->dpi, rf, + fd->glyph_index_shm, fd->mempool_shm, + fd->file ? _shared_string_get(fd->file) : ""); + } + + printf_newline(1); +} + +static void +_glyphs_all_print(Shm_File *sf) +{ + int k; + int nglyphs = 0; + int mem_used = 0; + + printf(" GlyphID Refcnt Index Size Rows Width Pitch Grays Mode " + "BufID Offset ShmPath\n"); + + for (k = 0; k < sf->header->count; k++) + { + Glyph_Data *gd; + + gd = _shared_array_item_get(sf, k); + if (!gd) break; + if (!gd->id) continue; + + printf(" %8u %6u %6u %5u %5u %5u %5u %5u %5u %6u %6u '%s'\n", + gd->id, gd->refcount, gd->index, gd->size, gd->rows, gd->width, + gd->pitch, gd->num_grays, gd->pixel_mode, gd->buffer_id, + gd->offset, _shared_string_get(gd->shm_id)); + + nglyphs++; + mem_used += gd->size; + } + + printf("Total %d glyph(s) loaded, using %d bytes (w/o padding)\n", + nglyphs, mem_used); +} + +static void +_fonts_all_print_full(void) +{ + int k; + + static const char *rend_flags[] = { "R", "S", "W", "SW", "X" }; + + if (!sf_fonts) return; + + printf("List of loaded fonts: %s\n", eina_file_filename_get(sf_fonts->f)); + printf("Rendering flags: " + "R: Regular, S: Slanted, W: Weight, X: Invalid\n\n"); + printf_newline(0); + + for (k = 0; k < sf_fonts->header->count; k++) + { + Shm_File *sf; + Font_Data *fd; + int rflag; + const char *rf; + + fd = _shared_array_item_get(sf_fonts, k); + if (!fd) break; + if (!fd->id) continue; + if (!fd->glyph_index_shm) continue; + + sf = _shm_file_open(_shared_string_get(fd->glyph_index_shm)); + if (!_shm_file_probe(sf)) + { + _shm_file_close(sf); + continue; + } + + rflag = fd->rend_flags; + if (rflag < 0 || rflag > 3) rflag = 4; + rf = rend_flags[rflag]; + + printf("Font #%-8d %d\n", k, fd->id); + printf("Refcount %d\n", fd->refcount); + printf("File '%s'\n", _shared_string_get(fd->file)); + printf("Name '%s'\n", + fd->name ? _shared_string_get(fd->name) : ""); + printf("Size %d\n", fd->size); + printf("DPI %d\n", fd->dpi); + printf("Rendering flag %s (%d)\n", rf, fd->rend_flags); + printf("Glyph index '%s'\n", _shared_string_get(fd->glyph_index_shm)); + printf("Glyph data '%s'\n", _shared_string_get(fd->mempool_shm)); + + _glyphs_all_print(sf); + + _shm_file_close(sf); + printf_newline(0); + } + + printf("\n\n"); + fflush(stdout); +} + + +int +main(int argc EINA_UNUSED, char **argv EINA_UNUSED) +{ + Eina_List *opened_sf = NULL; + Eina_List *shmfiles = NULL, *l1, *l2; + const char *shmfolder = SHM_FOLDER; + Eina_Bool full = EINA_FALSE; + Shm_File *sf; + char *name; + struct winsize w; + + if (isatty(STDOUT_FILENO)) + { + ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); + _termsize = w.ws_col; + } + + if (argc > 1) + { + if (!strcmp(argv[1], "-h")) + { + printf("Usage: %s [-f] [folder]\n", argv[0]); + return 0; + } + else if (!strcmp(argv[1], "-f")) + { + full = EINA_TRUE; + if (argc > 2) + shmfolder = argv[2]; + } + else + shmfolder = argv[1]; + } + + eina_init(); + _evas_cserve2_shm_debug_log_dom = eina_log_domain_register + ("evas_cserve2_shm_debug", EINA_COLOR_BLUE); + + shmfiles = _shm_files_list(shmfolder); + if (!shmfiles) + { + WRN("No shm file was found in %s", shmfolder); + goto finish; + } + + DBG("Found %d files in %s", eina_list_count(shmfiles), shmfolder); + + // Look for strings index & mempool + EINA_LIST_FOREACH_SAFE(shmfiles, l1, l2, name) + { + sf = _shm_file_open(name); + if (!_shm_file_probe(sf)) + { + shmfiles = eina_list_remove_list(shmfiles, l1); + _shm_file_close(sf); + free(name); + continue; + } + + if (!sf->tag) + _shm_file_close(sf); + else + opened_sf = eina_list_append(opened_sf, sf); + + if (!!sf_strindex + && !!sf_strpool + && !!sf_fonts + && !!sf_images + && !!sf_files) + break; + } + + if (!sf_strindex || !sf_strpool) + { + ERR("Could not identify strings memory pool"); + goto finish; + } + + _index_tables_summary_print(); + _strings_all_print(full); + _files_all_print(full); + _images_all_print_short(); + if (full) _images_all_print_full(); + _fonts_all_print_short(); + if (full) _fonts_all_print_full(); + +finish: + EINA_LIST_FREE(opened_sf, sf) + _shm_file_close(sf); + + EINA_LIST_FREE(shmfiles, name) + free(name); + + eina_shutdown(); + return 0; +}