Tips for troubleshooting bottlenecks and optimizing resource usage
Optimization of performance in desktop interop deployments impacts end-user productivity and reduces the total cost of operation. Here at interop.io, we’ve identified five key factors that influence performance in real-world desktop environments.
1. Disk footprint
Desktop interop systems like io.Connect Desktop are typically installed as launchable applications on end users’ computers or VDIs. The amount of disk space required for installation varies depending on the specific feature set in use. For instance, the inclusion of various adapters (e.g, Office Adapter) increases the required disk space. System logging also requires adequate disk space. The parameters of io.Connect’s log rotation (zipping and then removing old files) can be adjusted as necessary to ensure that systems never run low on disk space.
Free Trial vs. Production size
Note that trial versions of io.Connect Desktop have larger disk footprint than production versions. This is because the trial version includes io.Connect Desktop’s full suite of adapters and libraries. We optimize this size when configuring your production installer.
2. Memory footprint
The amount of memory used by a desktop system depends on 4 factors:
- Baseline system memory. This is the memory required by the system’s core components and service layers. This is a fixed amount which cannot be optimized.
- App memory requirements. This is the most important factor. Each app that is launched inside the desktop will have its own memory requirements. This memory usage is typically independent of the underlying platform. For instance, an app running in a Chrome tab will use the same amount of memory running in an io.Connect window.
- System overhead per app. The desktop system will add additional memory for each running app. This includes the cost for running the underlying rendering engine (e.g. chromium instances, webview2 instances) as well as the desktop system’s own memory requirements (such as client-side APIs that are resident in the app, e.g. via preloads). This overhead is typically the same in Chrome and io.Connect.
- Systemwide heap. App usage of features such as stored contexts, application configs, etc will result in some memory growth at the system level. The exact amount depends both on the behaviors of apps as well as the heuristics of the system itself. This memory is usually small unless very large contexts or extensive lists of apps are used.
It is important to note that overall memory requirements of the desktop don’t impact end-user experience until memory requirements overshoot the hardware’s capacity, at which point hardware systems can slow down due to memory swapping. Some VDI systems can fail outright when memory requirements are exceeded. Modern hardware typically provides 16GB and 32GB options at low cost. VDI systems with these capacities can cost $200 - $400 per month, per end user.
Greedy memory allocation
A key understanding when evaluating memory usage is that modern operating systems use a “greedy” approach to allocating memory. App memory may swell in size as the operating system determines the app’s needs, and the OS will not necessarily reclaim that memory until it is needed. In a system with 32GB of memory, it may be the case that the operating system rarely needs to reclaim memory, and so a large app like io.Connect or Chrome may be observed to have very high memory usage, even though much of this memory is not “active”.
Considerations
A key value proposition of desktop interop is the ability to run multiple apps at once in a “composed” view. Such a view can be a layout (multiple windows organized across one or more monitors) or a workspace (multiple apps organized into frames within a single window). With more windows comes a requirement for more memory, each app requiring its own heap as well as the memory requirements of the underlying rendering engine (Chromium). For large layouts across multiple monitors, this can result in a claim for several gigabytes of memory.
Individual app consumption
It is important to understand the memory requirements of the individual apps that will be running simultaneously on the screen. For instance, an app that requires 400MB of memory running in a browser tab might never seem to cause any problems. But once released within io.Connect, users can decide to open several copies of the same app (now that they can organize these copies side-by-side), which then multiplies the amount of memory required. Optimizing memory usage of your business apps may therefore be necessary when system resources are constrained.
3. CPU and networking overhead
In much the same way as a browser does, the bulk of CPU usage is generally from the applications that reside within the desktop. A desktop system does add some CPU and networking overhead via its own underlying processes, most of which occur only during system startup. Some overhead occurs when client APIs are used within the application space. For instance, applications that share context must exchange that context via the system’s services. Those services will use CPU to process and communicate. Generally, the overhead of such systems is low, but in some cases can become noticeable, such as when exchanging large chunks of data, when adding large numbers of app configs, or when saving and restoring complex layouts.
Delays due to overloaded CPU or network can negatively impact end-user experience. Typically, such situations are remedied through tweaks to API usage or through revisions to app architecture.
See how to check an app’s CPU and memory usage in the logs - Examining logs in practice
4. Window launch latency
What causes launch latency
Whenever an app is launched, a “renderer” must be instantiated to contain the app. Each of these renderers is its own Chromium instance, launched at the operating system level and observable in task manager. Once the renderer is launched, it immediately loads the app (e.g. downloading its HTML and JavaScript from a network), compiles (V8 engine), and then runs it. The app itself then may have its own initialization process, eventually resulting in display of its contents to the end user (e.g. React rendering). This overall process is essentially the same in interop.io as it is when opening a URL into a new browser tab in Chrome.
To the end-user, latency is a question of perception. The end user subconsciously measures latency as the time between when they click to launch an app until the time that the app is visible and interactive. As developers, we must break down this experience into individual steps for optimization:
- Time from click to launching of the renderer
- Time from launch of the renderer to running of application code
- Time from running application code to the app being ready for interaction
Of these, the first step involves the menu itself responding to the end user, and then the desktop system’s internal relays which trigger the launch of a renderer. This first step generally occurs quickly (but should not be ignored.)
The second step (launching a renderer) depends on the performance of the underlying platform architecture as well as the operating system itself. The amount of time depends in some part on the underlying hardware as this is a CPU-intensive moment. Restoration of a layout may involve launching many apps simultaneously, which can take longer even on powerful systems, particularly if the apps themselves are complex and therefore contending for CPU resources. This is akin to restoring Chrome with dozens of tabs open. Multi-core systems are essential to delivering a better user experience.
See how to track Layout restoration in the logs here - Examining logs in practice
Optimizing time to interactive (TTI) and first contentful paint (FCP)
In the third step, the applications themselves must be optimized for quick display. It is common to optimize web apps for metrics such as “Time To Interactive” (TTI) or “First Contentful Paint” (FCP). These same types of optimizations should be considered for apps that run inside a desktop.
It’s worth noting first that an improvement of 1 or 2 seconds of window launch time is probably not meaningful in the context of a worker’s day. It is only when switching large layouts that an end user generally feels any sense of slowness, and in most of our experience, the biggest gains can be had by optimizing the footprint of individual apps.
5. Desktop startup time
The final performance consideration is how long the desktop itself takes to launch. An end user is likely to perceive this as the time from double-clicking on the desktop icon to the time when the initial layout is loaded, and all the apps are interactive. As such, a large portion of desktop startup time is actually layout loading time, which corresponds directly to window launch times as discussed above. But any slowness with window launch times may be exacerbated during startup due to contention with system resources which are booting and initializing at the same time as the apps.
Desktop startup time depends greatly on the level of “infrastructure” that a firm requires to operate their desktop. By “infrastructure” we mean services which are run during the startup process. In raw form, io.Connect starts in about 10 seconds, but launching and sequencing of background services and other support applications can cause this startup time to balloon. As this sort of infrastructure grows in complexity, CPU and network contention become more likely (as mentioned above), which can further exacerbate startup times. A good practice to avoid these conditions is to limit the number of services by consolidating startup code into fewer, or even a single service.
Cost vs. Gain
It is worth noting that system startup time is generally a once-per-day occurrence. A startup time of 30-60 seconds is not ideal, but may not be worth huge effort to optimize unless usage is truly negatively impacted. If systems need to be restarted daily, then this can be accomplished through settings in io.Connect, which would allow the restart to occur during off-hours, so that users are not impacted.
Key takeaways for desktop interop performance optimization
We must not forget that the user experience interoperability achieves is seamless, but behind the scenes, an often not-so-powerful machine needs to handle dozens of applications at the same time. Sometimes, just one of them can be causing issues and needs to be investigated. In other cases, the cumulative load becomes too great. Balancing disk usage, memory, CPU, and startup processes can significantly improve both performance and user satisfaction. By continuously monitoring resource utilization and refining app configurations, organizations can maintain responsive, scalable desktop environments. In both cases io.Insights can be the tool that makes investigation and performance monitoring much faster, covering every little metric and app trace. See example: Track down issues fast with io.Insights