diff --git a/android/jni/com/mapswithme/core/logging.cpp b/android/jni/com/mapswithme/core/logging.cpp index 4a50ef4875..0539454224 100644 --- a/android/jni/com/mapswithme/core/logging.cpp +++ b/android/jni/com/mapswithme/core/logging.cpp @@ -3,15 +3,11 @@ #include #include -#include "../../../../../base/assert.hpp" #include "../../../../../base/logging.hpp" #include "../../../../../base/exception.hpp" #include "../../../../../coding/file_writer.hpp" #include "../../../../../platform/platform.hpp" - -#include "../../../../../std/unique_ptr.hpp" - -//#define MWM_LOG_TO_FILE +#include "../../../../../platform/file_logging.hpp" namespace jni @@ -36,28 +32,10 @@ void AndroidLogMessage(LogLevel l, SrcPoint const & src, string const & s) __android_log_write(pr, "MapsWithMe_JNI", out.c_str()); } -void AndroidLogToFile(LogLevel l, SrcPoint const & src, string const & s) -{ - static unique_ptr file; - - if (file == NULL) - { - if (GetPlatform().WritableDir().empty()) - return; - - file.reset(new FileWriter(GetPlatform().WritablePathForFile("logging.txt"))); - } - - string srcString = DebugPrint(src) + " " + s + "\n"; - - file->Write(srcString.c_str(), srcString.size()); - file->Flush(); -} - void AndroidAssertMessage(SrcPoint const & src, string const & s) { #if defined(MWM_LOG_TO_FILE) - AndroidLogToFile(LERROR, src, s); + LogMessageFile(LERROR, src, s); #else AndroidLogMessage(LERROR, src, s); #endif @@ -72,7 +50,7 @@ void AndroidAssertMessage(SrcPoint const & src, string const & s) void InitSystemLog() { #if defined(MWM_LOG_TO_FILE) - SetLogMessageFn(&AndroidLogToFile); + SetLogMessageFn(&LogMessageFile); #else SetLogMessageFn(&AndroidLogMessage); #endif diff --git a/android/jni/com/mapswithme/maps/MapFragment.cpp b/android/jni/com/mapswithme/maps/MapFragment.cpp index cf8a4062f0..5e90487ad5 100644 --- a/android/jni/com/mapswithme/maps/MapFragment.cpp +++ b/android/jni/com/mapswithme/maps/MapFragment.cpp @@ -15,6 +15,8 @@ #include "../../../../../base/logging.hpp" +#include "../../../../../platform/file_logging.hpp" + extern "C" { @@ -52,6 +54,7 @@ extern "C" if (speed > 0.0) info.m_speed = speed; + LogMemoryInfo(); g_framework->OnLocationUpdated(info); } diff --git a/android/jni/com/mapswithme/platform/Platform.cpp b/android/jni/com/mapswithme/platform/Platform.cpp index 2117cdde8a..2e3a891583 100644 --- a/android/jni/com/mapswithme/platform/Platform.cpp +++ b/android/jni/com/mapswithme/platform/Platform.cpp @@ -55,6 +55,29 @@ string Platform::UniqueClientId() const return res; } +string Platform::GetMemoryInfo() const +{ + JNIEnv * env = jni::GetEnv(); + if (!env) + { + LOG(LWARNING, ("Can't get JNIEnv")); + return string(""); + } + + jclass memLoggingClass = env->FindClass("com/mapswithme/util/log/MemLogging"); + ASSERT(memLoggingClass, ()); + + jmethodID getMemoryInfoId = env->GetStaticMethodID(memLoggingClass, "GetMemoryInfo", "()Ljava/lang/String;"); + ASSERT(getMemoryInfoId, ()); + + jstring memInfoString = (jstring)env->CallStaticObjectMethod(memLoggingClass, getMemoryInfoId); + ASSERT(memInfoString, ()); + + string res = jni::ToNativeString(env, memInfoString); + + return res; +} + void Platform::RunOnGuiThread(TFunctor const & fn) { android::Platform::RunOnGuiThreadImpl(fn); diff --git a/android/src/com/mapswithme/maps/MWMActivity.java b/android/src/com/mapswithme/maps/MWMActivity.java index 8e97bc0230..6697703975 100644 --- a/android/src/com/mapswithme/maps/MWMActivity.java +++ b/android/src/com/mapswithme/maps/MWMActivity.java @@ -75,7 +75,6 @@ import com.mapswithme.util.ShareAction; import com.mapswithme.util.UiUtils; import com.mapswithme.util.Utils; import com.mapswithme.util.Yota; -import com.mapswithme.util.log.MemLogging; import com.mapswithme.util.statistics.Statistics; import com.nineoldandroids.animation.Animator; import com.nineoldandroids.animation.ObjectAnimator; @@ -153,7 +152,6 @@ public class MWMActivity extends BaseMwmFragmentActivity private LocationPredictor mLocationPredictor; private LikesManager mLikesManager; - private MemLogging mMemLogging; public static Intent createShowMapIntent(Context context, Index index, boolean doAutoDownload) { @@ -582,7 +580,6 @@ public class MWMActivity extends BaseMwmFragmentActivity mLocationPredictor = new LocationPredictor(new Handler(), this); mLikesManager = new LikesManager(this); - mMemLogging = new MemLogging(this); restoreRoutingState(savedInstanceState); } @@ -1029,14 +1026,11 @@ public class MWMActivity extends BaseMwmFragmentActivity mPlacePage.onResume(); mLocationPredictor.resume(); mLikesManager.showLikeDialogs(); - mMemLogging.startLogging(); } @Override protected void onPause() { - mMemLogging.stopLogging(); - pauseLocation(); stopWatchingExternalStorage(); stopWatchingCompassStatusUpdate(); diff --git a/android/src/com/mapswithme/util/log/MemLogging.java b/android/src/com/mapswithme/util/log/MemLogging.java index 1344168c4c..1800657150 100644 --- a/android/src/com/mapswithme/util/log/MemLogging.java +++ b/android/src/com/mapswithme/util/log/MemLogging.java @@ -3,63 +3,36 @@ package com.mapswithme.util.log; import android.app.ActivityManager; import android.content.Context; import android.os.Debug; -import android.os.Handler; -import android.util.Log; -import com.mapswithme.maps.BuildConfig; import android.os.Build; +import com.mapswithme.maps.MWMApplication; +import java.text.DateFormat; +import java.util.Date; public class MemLogging { - private final static String TAG = "MemLogging"; - private Context mContext; - private Handler mHandler; - - private Runnable logging = new Runnable() + public static String GetMemoryInfo() { - @Override - public void run() + final Debug.MemoryInfo debugMI = new Debug.MemoryInfo(); + Debug.getMemoryInfo(debugMI); + final ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo(); + final Context content = MWMApplication.get().getApplicationContext(); + final ActivityManager activityManager = + (ActivityManager) content.getSystemService(content.ACTIVITY_SERVICE); + activityManager.getMemoryInfo(mi); + StringBuilder log = new StringBuilder("Memory info: " + + " Debug.getNativeHeapSize() = " + Debug.getNativeHeapSize() / 1024 + + "KB; Debug.getNativeHeapAllocatedSize() = " + Debug.getNativeHeapAllocatedSize() / 1024 + + "KB; Debug.getNativeHeapFreeSize() = " + Debug.getNativeHeapFreeSize() / 1024 + + "KB; debugMI.getTotalPrivateDirty() = " + debugMI.getTotalPrivateDirty() + + "KB; debugMI.getTotalPss() = " + debugMI.getTotalPss() + + "KB; mi.availMem = " + mi.availMem / 1024 + + "KB; mi.threshold = " + mi.threshold / 1024 + + "KB; mi.lowMemory = " + mi.lowMemory); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - final Debug.MemoryInfo debugMI = new Debug.MemoryInfo(); - Debug.getMemoryInfo(debugMI); - final ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo(); - final ActivityManager activityManager = - (ActivityManager) mContext.getSystemService(mContext.ACTIVITY_SERVICE); - activityManager.getMemoryInfo(mi); - StringBuilder log = new StringBuilder("Memory info: Debug.getNativeHeapSize() = " + Debug.getNativeHeapSize() / 1024 + - "KB; Debug.getNativeHeapAllocatedSize() = " + Debug.getNativeHeapAllocatedSize() / 1024 + - "KB, Debug.getNativeHeapFreeSize() = " + Debug.getNativeHeapFreeSize() / 1024 + - "KB. debugMI.getTotalPrivateDirty() = " + debugMI.getTotalPrivateDirty() + - "KB. debugMI.getTotalPss() = " + debugMI.getTotalPss() + - "KB. mi.availMem = " + mi.availMem / 1024 + - "KB. mi.threshold = " + mi.threshold / 1024 + - "KB. mi.lowMemory = " + mi.lowMemory + " "); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) - { - log.append("mi.totalMem = " + mi.totalMem / 1024 + "KB."); - } - Log.d(TAG, log.toString()); - - final long memLogPeriod = 3000; - mHandler.postDelayed(logging, memLogPeriod); + log.append(" mi.totalMem = " + mi.totalMem / 1024 + "KB."); } - }; - - public MemLogging(Context context) - { - mContext = context; - mHandler = new Handler(); - } - - public void startLogging() - { - if (BuildConfig.DEBUG) - mHandler.post(logging); - } - - public void stopLogging() - { - if (BuildConfig.DEBUG) - mHandler.removeCallbacks(logging); + return log.toString(); } } diff --git a/graphics/resource_manager.cpp b/graphics/resource_manager.cpp index 05f3d334ec..43a1ee6ce5 100644 --- a/graphics/resource_manager.cpp +++ b/graphics/resource_manager.cpp @@ -73,7 +73,6 @@ namespace graphics res.m_indices->lock(); res.m_vertices->lock(); } - return res; } diff --git a/graphics/resource_manager.hpp b/graphics/resource_manager.hpp index 4444c46dfb..e585dbcaa5 100644 --- a/graphics/resource_manager.hpp +++ b/graphics/resource_manager.hpp @@ -6,7 +6,6 @@ #include "data_formats.hpp" #include "defines.hpp" -//#include "../base/mutex.hpp" #include "../base/resource_pool.hpp" #include "../std/shared_ptr.hpp" diff --git a/iphone/Maps/Classes/MapViewController.mm b/iphone/Maps/Classes/MapViewController.mm index 79c7edd176..06bca27e54 100644 --- a/iphone/Maps/Classes/MapViewController.mm +++ b/iphone/Maps/Classes/MapViewController.mm @@ -30,6 +30,7 @@ #include "../../../map/user_mark.hpp" #include "../../../map/country_status_display.hpp" #include "../../../platform/settings.hpp" +#include "../../../platform/file_logging.hpp" #define ALERT_VIEW_FACEBOOK 1 #define ALERT_VIEW_APPSTORE 2 @@ -133,6 +134,7 @@ [m_predictor reset:info]; Framework & frm = GetFramework(); frm.OnLocationUpdate(info); + LogMemoryInfo(); [self showPopover]; [self updateRoutingInfo]; diff --git a/iphone/Maps/main.mm b/iphone/Maps/main.mm index 774873b950..779d1979d4 100644 --- a/iphone/Maps/main.mm +++ b/iphone/Maps/main.mm @@ -4,8 +4,7 @@ #include "../../platform/settings.hpp" #include "../../platform/platform.hpp" - -#include "../../base/logging.hpp" +#include "../../platform/file_logging.hpp" /// Used to trick iOs and enable multithreading support with non-native pthreads. @@ -19,6 +18,9 @@ int main(int argc, char * argv[]) { +#ifdef MWM_LOG_TO_FILE + my::SetLogMessageFn(LogMessageFile); +#endif LOG(LINFO, ("maps.me started, detected CPU cores:", GetPlatform().CpuCores())); int retVal; diff --git a/map/framework.cpp b/map/framework.cpp index de44bc6c8b..f1607f3cf6 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -951,9 +951,8 @@ void Framework::ClearAllCaches() void Framework::MemoryWarning() { - ClearAllCaches(); - LOG(LINFO, ("MemoryWarning")); + ClearAllCaches(); } void Framework::EnterBackground() diff --git a/platform/file_logging.cpp b/platform/file_logging.cpp new file mode 100644 index 0000000000..edaef6a4af --- /dev/null +++ b/platform/file_logging.cpp @@ -0,0 +1,59 @@ +#include "file_logging.hpp" + +#include "../base/mutex.hpp" + +#include "../std/chrono.hpp" + +#include "../coding/file_writer.hpp" + +#include "../platform/platform.hpp" + + +void LogMessageFile(my::LogLevel level, my::SrcPoint const & srcPoint, string const & msg) +{ + static threads::Mutex mutex; + + threads::MutexGuard guard(mutex); + UNUSED_VALUE(guard); + + static unique_ptr file; + + if (file == nullptr) + { + if (GetPlatform().WritableDir().empty()) + return; + auto const curTime = system_clock::now(); + time_t const curCTime = system_clock::to_time_t(curTime); + tm * curTimeTM = localtime(&curCTime); + assert(curTimeTM != nullptr); + stringstream fileName; + fileName << "logging_" << curTimeTM->tm_year + 1900 << "_" << curTimeTM->tm_mon + 1 << "_" << curTimeTM->tm_mday << "_" + << curTimeTM->tm_hour << "_" << curTimeTM->tm_min << "_" << curTimeTM->tm_sec << ".txt"; + file.reset(new FileWriter(GetPlatform().WritablePathForFile(fileName.str()))); + } + + string srcString = DebugPrint(srcPoint) + " " + msg + "\n"; + + file->Write(srcString.c_str(), srcString.size()); + file->Flush(); +} + +void LogMemoryInfo() +{ +#ifdef DEBUG + static unsigned long counter = 0; + const unsigned short writeLogEveryNthLocationUpdate = 3; + if (counter % writeLogEveryNthLocationUpdate == 0) + { + auto const curTime = system_clock::now(); + time_t const curCTime = system_clock::to_time_t(curTime); + tm * curTimeTM = localtime(&curCTime); + ASSERT(curTimeTM != nullptr, ()); + stringstream fileName; + fileName << " " << curTimeTM->tm_year + 1900 << "." << curTimeTM->tm_mon + 1 << "." << curTimeTM->tm_mday << " " + << curTimeTM->tm_hour << ":" << curTimeTM->tm_min << ":" << curTimeTM->tm_sec << " "; + LOG(LDEBUG, (fileName.str(), GetPlatform().GetMemoryInfo())); + } + ++counter; +#endif +} diff --git a/platform/file_logging.hpp b/platform/file_logging.hpp new file mode 100644 index 0000000000..7887a171e8 --- /dev/null +++ b/platform/file_logging.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include "../base/logging.hpp" + +// If you uncomment the line bellow the application log will be written to a file. +// You'll fild the file in MapsWithMe directory on Android platform and in Documents on iOS. +// #define MWM_LOG_TO_FILE + +void LogMessageFile(my::LogLevel level, my::SrcPoint const & srcPoint, string const & msg); +void LogMemoryInfo(); diff --git a/platform/platform.hpp b/platform/platform.hpp index a66a9036e9..c1e6769faf 100644 --- a/platform/platform.hpp +++ b/platform/platform.hpp @@ -164,6 +164,10 @@ public: bool IsTablet() const { return m_isTablet; } + /// @return information about kinds of memory which are relevant for a platform + /// This methid is implemented for iOS and Android only + string GetMemoryInfo() const; + private: void GetSystemFontNames(FilesList & res) const; }; diff --git a/platform/platform.pro b/platform/platform.pro index 4437ec4c46..dba33ba767 100644 --- a/platform/platform.pro +++ b/platform/platform.pro @@ -71,7 +71,8 @@ HEADERS += \ http_thread_callback.hpp \ chunks_download_strategy.hpp \ servers_list.hpp \ - constants.hpp + constants.hpp \ + file_logging.hpp \ SOURCES += \ preferred_languages.cpp \ @@ -80,4 +81,5 @@ SOURCES += \ http_request.cpp \ chunks_download_strategy.cpp \ platform.cpp \ - servers_list.cpp + servers_list.cpp \ + file_logging.cpp \ diff --git a/platform/platform_ios.mm b/platform/platform_ios.mm index d30f3eb6fa..b0f9481afa 100644 --- a/platform/platform_ios.mm +++ b/platform/platform_ios.mm @@ -15,6 +15,8 @@ #define IFT_ETHER 0x6 /* Ethernet CSMACD */ #endif +#import + #import #import #import @@ -145,6 +147,29 @@ static void PerformImpl(void * obj) delete f; } +string Platform::GetMemoryInfo() const +{ + struct task_basic_info info; + mach_msg_type_number_t size = sizeof(info); + kern_return_t const kerr = task_info(mach_task_self(), + TASK_BASIC_INFO, + (task_info_t)&info, + &size); + stringstream ss; + if (kerr == KERN_SUCCESS) + { + ss << "Memory info: Resident_size = " << info.resident_size / 1024 + << "KB; virtual_size = " << info.resident_size / 1024 << "KB; suspend_count = " << info.suspend_count + << " policy = " << info.policy; + return ss.str(); + } + else + { + ss << "Error with task_info(): " << mach_error_string(kerr); + return ss.str(); + } +} + void Platform::RunOnGuiThread(TFunctor const & fn) { dispatch_async_f(dispatch_get_main_queue(), new TFunctor(fn), &PerformImpl); diff --git a/std/chrono.hpp b/std/chrono.hpp index 140a053396..d93f8ad24f 100644 --- a/std/chrono.hpp +++ b/std/chrono.hpp @@ -11,6 +11,8 @@ using std::chrono::duration_cast; using std::chrono::high_resolution_clock; using std::chrono::milliseconds; using std::chrono::nanoseconds; +using std::chrono::duration_cast; +using std::chrono::system_clock; #ifdef DEBUG_NEW #define new DEBUG_NEW