diff --git a/config.def.h b/config.def.h index 570f51f43a..7ecc3dec5f 100644 --- a/config.def.h +++ b/config.def.h @@ -717,6 +717,9 @@ static const bool playlist_show_core_name = false; static const bool playlist_show_sublabels = false; +/* Specifies which runtime record to use on playlist sublabels */ +static unsigned playlist_sublabel_runtime_type = PLAYLIST_RUNTIME_PER_CORE; + /* Show Menu start-up screen on boot. */ static const bool default_menu_show_start_screen = true; @@ -794,6 +797,9 @@ static const bool desktop_menu_enable = true; /* Keep track of how long each core+content has been running for over time */ static const bool content_runtime_log = false; +/* Keep track of how long each content has been running for over time (ignores core) */ +static const bool content_runtime_log_aggregate = false; + #if defined(__QNX__) || defined(_XBOX1) || defined(_XBOX360) || defined(__CELLOS_LV2__) || (defined(__MACH__) && defined(IOS)) || defined(ANDROID) || defined(WIIU) || defined(HAVE_NEON) || defined(GEKKO) || defined(__ARM_NEON__) static enum resampler_quality audio_resampler_quality_level = RESAMPLER_QUALITY_LOWER; #elif defined(PSP) || defined(_3DS) || defined(VITA) || defined(PS2) diff --git a/configuration.c b/configuration.c index 55d67b7a75..1e8b0b4f06 100644 --- a/configuration.c +++ b/configuration.c @@ -1578,7 +1578,8 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings, #endif SETTING_BOOL("playlist_use_old_format", &settings->bools.playlist_use_old_format, true, playlist_use_old_format, false); - SETTING_BOOL("content_runtime_log", &settings->bools.content_runtime_log, true, content_runtime_log, false); + SETTING_BOOL("content_runtime_log", &settings->bools.content_runtime_log, true, content_runtime_log, false); + SETTING_BOOL("content_runtime_log_aggregate", &settings->bools.content_runtime_log_aggregate, true, content_runtime_log_aggregate, false); SETTING_BOOL("playlist_show_sublabels", &settings->bools.playlist_show_sublabels, true, playlist_show_sublabels, false); SETTING_BOOL("playlist_show_core_name", &settings->bools.playlist_show_core_name, true, playlist_show_core_name, false); SETTING_BOOL("playlist_sort_alphabetical", &settings->bools.playlist_sort_alphabetical, true, playlist_sort_alphabetical, false); @@ -1762,6 +1763,8 @@ static struct config_uint_setting *populate_settings_uint(settings_t *settings, SETTING_UINT("libnx_overclock", &settings->uints.libnx_overclock, true, SWITCH_DEFAULT_CPU_PROFILE, false); #endif + SETTING_UINT("playlist_sublabel_runtime_type", &settings->uints.playlist_sublabel_runtime_type, true, playlist_sublabel_runtime_type, false); + *size = count; return tmp; diff --git a/configuration.h b/configuration.h index 517da9e807..25c82a2094 100644 --- a/configuration.h +++ b/configuration.h @@ -309,6 +309,7 @@ typedef struct settings bool sustained_performance_mode; bool playlist_use_old_format; bool content_runtime_log; + bool content_runtime_log_aggregate; bool playlist_show_core_name; bool playlist_sort_alphabetical; @@ -438,6 +439,8 @@ typedef struct settings unsigned menu_rgui_internal_upscale_level; unsigned menu_ticker_type; + unsigned playlist_sublabel_runtime_type; + unsigned camera_width; unsigned camera_height; diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index 7fe4bdbf9c..1c25c99e8d 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -1789,9 +1789,13 @@ MSG_HASH(MENU_ENUM_LABEL_MENU_SOUND_BGM, "menu_sound_bgm") MSG_HASH(MENU_ENUM_LABEL_CONTENT_RUNTIME_LOG, "content_runtime_log") +MSG_HASH(MENU_ENUM_LABEL_CONTENT_RUNTIME_LOG_AGGREGATE, + "content_runtime_log_aggregate") MSG_HASH(MENU_ENUM_LABEL_PLAYLIST_SHOW_CORE_NAME, "playlist_show_core_name") MSG_HASH(MENU_ENUM_LABEL_PLAYLIST_SORT_ALPHABETICAL, "playlist_sort_alphabetical") MSG_HASH(MENU_ENUM_LABEL_PLAYLIST_SHOW_SUBLABELS, "playlist_show_sublabels") +MSG_HASH(MENU_ENUM_LABEL_PLAYLIST_SUBLABEL_RUNTIME_TYPE, + "playlist_sublabel_runtime_type") diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index daf0544f1e..06c7d13575 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -8312,11 +8312,19 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_RUNTIME_LOG, - "Save content runtime log" + "Save runtime log (per core)" ) MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_RUNTIME_LOG, - "Keeps track of how long your content has been running over time." + "Keeps track of how long each item of content has run for, with records separated by core." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_RUNTIME_LOG_AGGREGATE, + "Save runtime log (aggregate)" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_RUNTIME_LOG_AGGREGATE, + "Keeps track of how long each item of content has run for, recorded as the aggregate total across all cores." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_SHOW_SUBLABELS, @@ -8324,7 +8332,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_PLAYLIST_SHOW_SUBLABELS, - "Shows additional information for each playlist entry, such as current core association and play time (if available). Has a variable performance impact." + "Shows additional information for each playlist entry, such as current core association and runtime (if available). Has a variable performance impact." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_SUBLABEL_CORE, @@ -8338,3 +8346,19 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_SUBLABEL_LAST_PLAYED, "Last Played:" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_SUBLABEL_RUNTIME_TYPE, + "Playlist sublabel runtime" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PLAYLIST_SUBLABEL_RUNTIME_TYPE, + "Selects which type of runtime log record to display on playlist sublabels. (Note that the corresponding runtime log must be enabled via the 'Saving' options menu)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_RUNTIME_PER_CORE, + "Per Core" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_PLAYLIST_RUNTIME_AGGREGATE, + "Aggregate" + ) diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index 7071270c82..24ae295f92 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -522,6 +522,8 @@ default_sublabel_macro(action_bind_sublabel_rgui_menu_color_theme, default_sublabel_macro(action_bind_sublabel_rgui_menu_theme_preset, MENU_ENUM_SUBLABEL_RGUI_MENU_THEME_PRESET) default_sublabel_macro(action_bind_sublabel_menu_rgui_thumbnail_downscaler, MENU_ENUM_SUBLABEL_MENU_RGUI_THUMBNAIL_DOWNSCALER) default_sublabel_macro(action_bind_sublabel_content_runtime_log, MENU_ENUM_SUBLABEL_CONTENT_RUNTIME_LOG) +default_sublabel_macro(action_bind_sublabel_content_runtime_log_aggregate, MENU_ENUM_SUBLABEL_CONTENT_RUNTIME_LOG_AGGREGATE) +default_sublabel_macro(action_bind_sublabel_playlist_sublabel_runtime_type, MENU_ENUM_SUBLABEL_PLAYLIST_SUBLABEL_RUNTIME_TYPE) default_sublabel_macro(action_bind_sublabel_menu_rgui_internal_upscale_level, MENU_ENUM_SUBLABEL_MENU_RGUI_INTERNAL_UPSCALE_LEVEL) default_sublabel_macro(action_bind_sublabel_menu_ticker_type, MENU_ENUM_SUBLABEL_MENU_TICKER_TYPE) default_sublabel_macro(action_bind_sublabel_menu_ticker_speed, MENU_ENUM_SUBLABEL_MENU_TICKER_SPEED) @@ -855,9 +857,12 @@ static int action_bind_sublabel_playlist_entry( msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PLAYLIST_SUBLABEL_CORE), core_name); - /* Get runtime info *if* runtime logging is enabled + /* Get runtime info *if* required runtime log is enabled * *and* this is a valid playlist type */ - if (!settings->bools.content_runtime_log) + if (((settings->uints.playlist_sublabel_runtime_type == PLAYLIST_RUNTIME_PER_CORE) && + !settings->bools.content_runtime_log) || + ((settings->uints.playlist_sublabel_runtime_type == PLAYLIST_RUNTIME_AGGREGATE) && + !settings->bools.content_runtime_log_aggregate)) return 0; /* Note: This looks heavy, but each string_is_equal() call will @@ -2376,6 +2381,12 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_CONTENT_RUNTIME_LOG: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_content_runtime_log); break; + case MENU_ENUM_LABEL_CONTENT_RUNTIME_LOG_AGGREGATE: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_content_runtime_log_aggregate); + break; + case MENU_ENUM_LABEL_PLAYLIST_SUBLABEL_RUNTIME_TYPE: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_playlist_sublabel_runtime_type); + break; case MENU_ENUM_LABEL_MENU_RGUI_INTERNAL_UPSCALE_LEVEL: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_menu_rgui_internal_upscale_level); break; diff --git a/menu/menu_defines.h b/menu/menu_defines.h index 411a3f7d04..6c73366c29 100644 --- a/menu/menu_defines.h +++ b/menu/menu_defines.h @@ -303,6 +303,13 @@ enum menu_input_ctl_state MENU_INPUT_CTL_DEINIT }; +enum playlist_sublabel_runtime +{ + PLAYLIST_RUNTIME_PER_CORE = 0, + PLAYLIST_RUNTIME_AGGREGATE, + PLAYLIST_RUNTIME_LAST +}; + typedef uintptr_t menu_texture_item; typedef struct menu_display_ctx_clearcolor diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index b25fcc6346..571e11192e 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -1335,7 +1335,10 @@ static int menu_displaylist_parse_playlist(menu_displaylist_info_t *info, goto error; /* Check whether runtime logging info should be parsed */ - if (settings->bools.content_runtime_log) + if (((settings->uints.playlist_sublabel_runtime_type == PLAYLIST_RUNTIME_PER_CORE) && + settings->bools.content_runtime_log) || + ((settings->uints.playlist_sublabel_runtime_type == PLAYLIST_RUNTIME_AGGREGATE) && + settings->bools.content_runtime_log_aggregate)) { /* Runtime logging is valid for every type of playlist *apart from* * images/music/video history */ @@ -1383,7 +1386,8 @@ static int menu_displaylist_parse_playlist(menu_displaylist_info_t *info, if (get_runtime) { runtime_log_t *runtime_log = NULL; - runtime_log = runtime_log_init(path, core_path); + runtime_log = runtime_log_init(path, core_path, + settings->uints.playlist_sublabel_runtime_type == PLAYLIST_RUNTIME_PER_CORE); if (runtime_log) { @@ -5379,6 +5383,9 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, menu_displaylist ret = menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_PLAYLIST_SHOW_SUBLABELS, PARSE_ONLY_BOOL, false); + ret = menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_PLAYLIST_SUBLABEL_RUNTIME_TYPE, + PARSE_ONLY_UINT, false); ret = menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_PLAYLIST_SHOW_CORE_NAME, PARSE_ONLY_BOOL, false); @@ -5503,6 +5510,9 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, menu_displaylist menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_CONTENT_RUNTIME_LOG, PARSE_ONLY_BOOL, false); + menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_CONTENT_RUNTIME_LOG_AGGREGATE, + PARSE_ONLY_BOOL, false); info->need_refresh = true; info->need_push = true; diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 778a1d3577..5094d995d2 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -1298,6 +1298,30 @@ static void setting_get_string_representation_crt_switch_resolution_super( snprintf(s, len, "%d", *setting->value.target.unsigned_integer); } +static void setting_get_string_representation_uint_playlist_sublabel_runtime_type( + rarch_setting_t *setting, + char *s, size_t len) +{ + if (!setting) + return; + + switch (*setting->value.target.unsigned_integer) + { + case PLAYLIST_RUNTIME_PER_CORE: + strlcpy(s, + msg_hash_to_str( + MENU_ENUM_LABEL_VALUE_PLAYLIST_RUNTIME_PER_CORE), + len); + break; + case PLAYLIST_RUNTIME_AGGREGATE: + strlcpy(s, + msg_hash_to_str( + MENU_ENUM_LABEL_VALUE_PLAYLIST_RUNTIME_AGGREGATE), + len); + break; + } +} + static int setting_action_left_analog_dpad_mode(rarch_setting_t *setting, bool wraparound) { unsigned port = 0; @@ -4967,6 +4991,21 @@ static bool setting_append_list( general_read_handler, SD_FLAG_NONE); + CONFIG_BOOL( + list, list_info, + &settings->bools.content_runtime_log_aggregate, + MENU_ENUM_LABEL_CONTENT_RUNTIME_LOG_AGGREGATE, + MENU_ENUM_LABEL_VALUE_CONTENT_RUNTIME_LOG_AGGREGATE, + content_runtime_log_aggregate, + MENU_ENUM_LABEL_VALUE_OFF, + MENU_ENUM_LABEL_VALUE_ON, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler, + SD_FLAG_NONE); + END_SUB_GROUP(list, list_info, parent_group); END_GROUP(list, list_info, parent_group); } @@ -9884,6 +9923,22 @@ static bool setting_append_list( SD_FLAG_NONE ); + CONFIG_UINT( + list, list_info, + &settings->uints.playlist_sublabel_runtime_type, + MENU_ENUM_LABEL_PLAYLIST_SUBLABEL_RUNTIME_TYPE, + MENU_ENUM_LABEL_VALUE_PLAYLIST_SUBLABEL_RUNTIME_TYPE, + playlist_sublabel_runtime_type, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler); + (*list)[list_info->index - 1].action_ok = &setting_action_ok_uint; + (*list)[list_info->index - 1].get_string_representation = + &setting_get_string_representation_uint_playlist_sublabel_runtime_type; + menu_settings_list_current_add_range(list, list_info, 0, PLAYLIST_RUNTIME_LAST-1, 1, true, true); + CONFIG_BOOL( list, list_info, &settings->bools.playlist_show_core_name, diff --git a/msg_hash.h b/msg_hash.h index 91867422b8..0e82694f5f 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -2276,15 +2276,20 @@ enum msg_hash_enums MENU_LABEL(MENU_SOUND_BGM), MENU_ENUM_LABEL_VALUE_VIDEO_DRIVER_FALLBACK, MENU_LABEL(CONTENT_RUNTIME_LOG), + MENU_LABEL(CONTENT_RUNTIME_LOG_AGGREGATE), MENU_LABEL(PLAYLIST_SHOW_CORE_NAME), MENU_LABEL(PLAYLIST_SORT_ALPHABETICAL), MENU_LABEL(PLAYLIST_SHOW_SUBLABELS), + MENU_LABEL(PLAYLIST_SUBLABEL_RUNTIME_TYPE), MENU_ENUM_LABEL_VALUE_PLAYLIST_SUBLABEL_CORE, MENU_ENUM_LABEL_VALUE_PLAYLIST_SUBLABEL_RUNTIME, MENU_ENUM_LABEL_VALUE_PLAYLIST_SUBLABEL_LAST_PLAYED, + MENU_ENUM_LABEL_VALUE_PLAYLIST_RUNTIME_PER_CORE, + MENU_ENUM_LABEL_VALUE_PLAYLIST_RUNTIME_AGGREGATE, + MSG_LAST }; diff --git a/retroarch.c b/retroarch.c index 61caa3b713..2baefe10e6 100644 --- a/retroarch.c +++ b/retroarch.c @@ -848,6 +848,28 @@ void rarch_core_runtime_tick(void) } } +static void update_runtime_log(bool log_per_core) +{ + runtime_log_t *runtime_log = NULL; + + /* Initialise runtime log file */ + runtime_log = runtime_log_init(runtime_content_path, runtime_core_path, log_per_core); + if (runtime_log) + { + /* Add additional runtime */ + runtime_log_add_runtime_usec(runtime_log, libretro_core_runtime_usec); + + /* Update 'last played' entry */ + runtime_log_set_last_played_now(runtime_log); + + /* Save runtime log file */ + runtime_log_save(runtime_log); + + /* Clean up */ + free(runtime_log); + } +} + #ifdef HAVE_THREADS void runloop_msg_queue_lock(void) { @@ -2464,28 +2486,16 @@ bool rarch_ctl(enum rarch_ctl_state state, void *data) n = 0; /* Just silence any potential gcc warnings... */ RARCH_LOG("%s\n",log); - /* Only write to file if logging is enabled *and* content has run - * for a non-zero length of time */ - if (settings->bools.content_runtime_log && libretro_core_runtime_usec > 0) + /* Only write to file if content has run for a non-zero length of time */ + if (libretro_core_runtime_usec > 0) { - runtime_log_t *runtime_log = NULL; + /* Per core logging */ + if (settings->bools.content_runtime_log) + update_runtime_log(true); - /* Initialise runtime log file */ - runtime_log = runtime_log_init(runtime_content_path, runtime_core_path); - if (runtime_log) - { - /* Add additional runtime */ - runtime_log_add_runtime_usec(runtime_log, libretro_core_runtime_usec); - - /* Update 'last played' entry */ - runtime_log_set_last_played_now(runtime_log); - - /* Save runtime log file */ - runtime_log_save(runtime_log); - - /* Clean up */ - free(runtime_log); - } + /* Aggregate logging */ + if (settings->bools.content_runtime_log_aggregate) + update_runtime_log(false); } /* Reset runtime + content/core paths, to prevent any diff --git a/runtime_file.c b/runtime_file.c index 5ae97c9de2..5550a46002 100644 --- a/runtime_file.c +++ b/runtime_file.c @@ -268,7 +268,7 @@ end: /* Initialise runtime log, loading current parameters * if log file exists. Returned object must be free()'d. * Returns NULL if content_path and/or core_path are invalid */ -runtime_log_t *runtime_log_init(const char *content_path, const char *core_path) +runtime_log_t *runtime_log_init(const char *content_path, const char *core_path, bool log_per_core) { settings_t *settings = config_get_ptr(); core_info_list_t *core_info = NULL; @@ -305,7 +305,11 @@ runtime_log_t *runtime_log_init(const char *content_path, const char *core_path) if (string_is_equal(core_path, "builtin") || string_is_equal(core_path, file_path_str(FILE_PATH_DETECT))) return NULL; - /* Get core name */ + /* Get core name + * Note: An annoyance - this is required even when + * we are performing aggregate (not per core) logging, + * since content name is sometimes dependent upon core + * (e.g. see TyrQuake below) */ core_info_get_list(&core_info); if (!core_info) @@ -330,11 +334,18 @@ runtime_log_t *runtime_log_init(const char *content_path, const char *core_path) "logs", sizeof(tmp_buf)); - fill_pathname_join( - log_file_dir, - tmp_buf, - core_name, - sizeof(log_file_dir)); + if (log_per_core) + { + fill_pathname_join( + log_file_dir, + tmp_buf, + core_name, + sizeof(log_file_dir)); + } + else + { + strlcpy(log_file_dir, tmp_buf, sizeof(log_file_dir)); + } if (string_is_empty(log_file_dir)) return NULL; diff --git a/runtime_file.h b/runtime_file.h index e7f0abac30..241975fe07 100644 --- a/runtime_file.h +++ b/runtime_file.h @@ -60,7 +60,7 @@ typedef struct /* Initialise runtime log, loading current parameters * if log file exists. Returned object must be free()'d. * Returns NULL if content_path and/or core_path are invalid */ -runtime_log_t *runtime_log_init(const char *content_path, const char *core_path); +runtime_log_t *runtime_log_init(const char *content_path, const char *core_path, bool log_per_core); /* Setters */