Index: mptrack/AbstractVstEditor.cpp
===================================================================
--- mptrack/AbstractVstEditor.cpp	(revision 24407)
+++ mptrack/AbstractVstEditor.cpp	(working copy)
@@ -514,6 +514,14 @@
 		if(m_VstPlugin.IsBypassed())
 			title += _T(" - Bypass");
 
+		double cpuUsage = 0.0;
+		{
+			CriticalSection cs;
+			if(m_VstPlugin.GetSoundFile().m_PlayState.m_totalClocks)
+				cpuUsage = m_VstPlugin.m_MixState.clockCycles * 100.0 / m_VstPlugin.GetSoundFile().m_PlayState.m_totalClocks;
+		}
+		title += MPT_CFORMAT(" [{}%]")(mpt::cfmt::flt(cpuUsage, 3));
+
 		SetWindowText(title);
 	}
 }
Index: mptrack/AbstractVstEditor.h
===================================================================
--- mptrack/AbstractVstEditor.h	(revision 24407)
+++ mptrack/AbstractVstEditor.h	(working copy)
@@ -97,7 +97,7 @@
 
 	virtual bool OpenEditor(CWnd *parent);
 	virtual void DoClose();
-	virtual void UpdateParamDisplays() { if(m_updateDisplay) { SetupMenu(true); m_updateDisplay = false; } }
+	virtual void UpdateParamDisplays() { SetTitle(); if(m_updateDisplay) { SetupMenu(true); m_updateDisplay = false; } }
 	virtual void UpdateParam(int32 /*param*/) { }
 	virtual void UpdateView(UpdateHint hint);
 
Index: soundlib/Fastmix.cpp
===================================================================
--- soundlib/Fastmix.cpp	(revision 24407)
+++ soundlib/Fastmix.cpp	(working copy)
@@ -21,6 +21,7 @@
 #include "MixerLoops.h"
 #include "MixFuncTable.h"
 #include "plugins/PlugInterface.h"
+#include "mpt/arch/x86_amd64.hpp"
 #include <cfloat>  // For FLT_EPSILON
 #include <algorithm>
 
@@ -573,6 +574,10 @@
 			IMixPlugin *mixPlug = plugin.pMixPlugin;
 			SNDMIXPLUGINSTATE &state = mixPlug->m_MixState;
 
+#if (MPT_COMPILER_MSVC || MPT_COMPILER_GCC || MPT_COMPILER_CLANG) && (MPT_ARCH_X86 || MPT_ARCH_AMD64)
+			uint64 startClock = mpt::arch::current::rdtsc();
+#endif
+
 			//We should only ever reach this point if the song is playing.
 			if (!mixPlug->IsSongPlaying())
 			{
@@ -612,6 +617,10 @@
 			{
 				masterHasInput = true;
 			}
+
+#if(MPT_COMPILER_MSVC || MPT_COMPILER_GCC || MPT_COMPILER_CLANG) && (MPT_ARCH_X86 || MPT_ARCH_AMD64)
+			state.clockCycles += mpt::arch::current::rdtsc() - startClock;
+#endif
 		}
 	}
 	// Convert mix buffer
@@ -667,6 +676,10 @@
 			float *pOutL = pMixL;
 			float *pOutR = pMixR;
 
+#if(MPT_COMPILER_MSVC || MPT_COMPILER_GCC || MPT_COMPILER_CLANG) && (MPT_ARCH_X86 || MPT_ARCH_AMD64)
+			uint64 startClock = mpt::arch::current::rdtsc();
+#endif
+
 			if (!plugin.IsOutputToMaster())
 			{
 				PLUGINDEX nOutput = plugin.GetOutputPlugin();
@@ -770,6 +783,10 @@
 				}
 			}
 			state.dwFlags &= ~SNDMIXPLUGINSTATE::psfHasInput;
+
+#if(MPT_COMPILER_MSVC || MPT_COMPILER_GCC || MPT_COMPILER_CLANG) && (MPT_ARCH_X86 || MPT_ARCH_AMD64)
+			state.clockCycles += mpt::arch::current::rdtsc() - startClock;
+#endif
 		}
 	}
 #ifdef MPT_INTMIXER
Index: soundlib/PlayState.h
===================================================================
--- soundlib/PlayState.h	(revision 24407)
+++ soundlib/PlayState.h	(working copy)
@@ -25,6 +25,7 @@
 	friend class CSoundFile;
 
 public:
+	uint64 m_totalClocks = 0;
 	samplecount_t m_lTotalSampleCount = 0;  // Total number of rendered samples
 protected:
 	samplecount_t m_nBufferCount = 0;  // Remaining number samples to render for this tick
Index: soundlib/plugins/PlugInterface.h
===================================================================
--- soundlib/plugins/PlugInterface.h	(revision 24407)
+++ soundlib/plugins/PlugInterface.h	(working copy)
@@ -44,6 +44,8 @@
 	uint32 inputSilenceCount = 0;      // How much silence has been processed? (for plugin auto-turnoff)
 	mixsample_t nVolDecayL = 0, nVolDecayR = 0; // End of sample click removal
 
+	uint64 clockCycles = 0;
+
 	void ResetSilence()
 	{
 		dwFlags |= psfHasInput;
Index: soundlib/Sndmix.cpp
===================================================================
--- soundlib/Sndmix.cpp	(revision 24407)
+++ soundlib/Sndmix.cpp	(working copy)
@@ -221,6 +221,15 @@
 {
 	MPT_ASSERT_ALWAYS(m_MixerSettings.IsValid());
 
+#if(MPT_COMPILER_MSVC || MPT_COMPILER_GCC || MPT_COMPILER_CLANG) && (MPT_ARCH_X86 || MPT_ARCH_AMD64)
+	uint64 startClock = mpt::arch::current::rdtsc();
+	for(SNDMIXPLUGIN &plugin : m_MixPlugins)
+	{
+		if(plugin.pMixPlugin)
+			plugin.pMixPlugin->m_MixState.clockCycles = 0;
+	}
+#endif
+
 	samplecount_t countRendered = 0;
 	samplecount_t countToRender = count;
 
@@ -387,6 +396,10 @@
 
 	// mix done
 
+#if(MPT_COMPILER_MSVC || MPT_COMPILER_GCC || MPT_COMPILER_CLANG) && (MPT_ARCH_X86 || MPT_ARCH_AMD64)
+	m_PlayState.m_totalClocks = mpt::arch::current::rdtsc() - startClock;
+#endif
+
 	return countRendered;
 
 }
Index: src/mpt/arch/x86_amd64.hpp
===================================================================
--- src/mpt/arch/x86_amd64.hpp	(revision 24407)
+++ src/mpt/arch/x86_amd64.hpp	(working copy)
@@ -1988,7 +1988,15 @@
 };
 
 
+#if MPT_COMPILER_MSVC || MPT_COMPILER_GCC || MPT_COMPILER_CLANG
 
+MPT_ATTR_ALWAYSINLINE MPT_INLINE_FORCE static uint64 rdtsc() noexcept {
+	return __rdtsc();
+}
+
+#endif // MPT_COMPILER_MSVC || MPT_COMPILER_GCC || MPT_COMPILER_CLANG
+
+
 } // namespace x86
 
 namespace amd64 = x86;
