Writing Energy-Efficient Windows* Store Applications for Mobile Devices: Impact of File I/O, Network Transfer and Sensor Usage on Platform Power

Download Article

Download Writing Energy-Efficient Windows* Store Applications for Mobile Devices: Impact of File I/O, Network Transfer and Sensor Usage on Platform Power [PDF 734KB]

1. Introduction

In the series of articles on “Writing Energy-Efficient Windows* Store Applications for Mobile Devices”, we have discussed the timer usage and the graphical API usage on the processor package power consumption. In this section, we will discuss the impact of File I/O, network transfer and sensor usage applications on the platform power consumption.

Modern mobile platforms include multiple hardware components except processors, like storage, network device, sensor units etc. All these devices consume power whenever powered on and may have different power states. Different devices have different power management policies.

In this article, we focus on the Windows* Store apps that utilize hardware components except processors. We will address the power usage of hardware components on mobile platforms. Then we will discuss with case studies how the platform power is impacted by some Windows* Runtime API usages related to the hardware components. The experiments in the case studies were executed on a tablet with Intel® Atom™ processor and a clean Windows 8 RTM build. We utilized an external power meter to collect the platform power. The display refresh rate of the platform is 60 frames per second (fps).

2. File I/O Access

Many mobile apps include file access to the storage media in the mobile platforms. For example, photo editing apps need read or write image files stored on the storage device. In this session, we have a case study on Windows runtime API usage related to file I/O access for improving energy efficiency.

2.1 Storage Device

Generally NAND-based memories like eMMCs (embedded Multi Media Card) and SSDs are widely utilized as the main storage peripherals in mobile platforms. It is non-volatile storage with high capacity and does not require power to retain data. Many of modern smartphones and tablets utilize eMMC. Many of modern laptops and Ultrabooks* utilize SSDs. Both eMMCs and SSDs include NAND-based flash memory dies and an embedded controller to manage the memory die usage.

The operations on NAND dies introduce the major power variance of NAND based memory devices. There are three kinds of major operations - Read, Program and Erase. The read/write requests from applications are passed, translated and/or combined to the major operations on NAND memory dies. The block sizes of reading/writing affects the performance and the platform power consumption. Also, the sequential or random access requests can impact the power and performance of the device.

We study the platform power and performance impact of reading/writing with various block sizes when sequential/random reads/writes are requested via Windows* Runtime APIs in a Windows* Store app.

2.2 Sequential/random Read/Write

Windows* Runtime provides APIs for sequential and random access to files on storage media.

2.2.1 Sequential Read/Write

Windows* Runtime supports file read and write operations. It provides APIs for create, read and write files as CreateFile2, ReadFile, WriteFile. These APIs can be utilized for synchronous file read and write. In our sample code, we utilize a basic file read/write class FileAccessReader. The construct of the class includes a call to CreateFile2 to create a file on disk. It has two methods (Read and Write) directly to call ReadFile and WriteFile to read/write a fixed amount of size from/to a file.

The sample code 1 shows the implementation of sequential reads in our case study.

void SeqReadFileButton_Click(Object^ sender, RoutedEventArgs^ e)
{
	    FileAccessReader^ pfileReaderWriter = ref new   
        FileAccessReader(
              ApplicationData::Current>LocalFolder,"test.dat");

	    Platform::Array<byte>^ tempfileData = ref new       
                   Platform::Array<byte>(m_blocksize);
	    BasicTimer^ deltatime = ref new BasicTimer();
	    for (long i=0; i< m_filesize/m_blocksize; i++)
	    {
	        tempfileData = pfileReaderWriter->Read(
                                       tempfileData->Length);
     }
	    deltatime->Update();
	    m_deltatime = deltatime->Delta;
      OutputTextBlock->Text = "File content to position " 
       + (pfileReaderWriter->GetPosition()).ToString()
       + ". UI thread block time is " + m_deltatime.ToString() 
       + " seconds.";
}

Sample Code 1. Sequentially read from a file with a fixed block size **

The sample code 2 shows the implementation of sequential writes in our case study.

void SeqWriteFileButton_Click(Object^ sender, RoutedEventArgs^ e)
{
	    FileAccessReader^ pfileReaderWriter = ref new   
        FileAccessReader(
              ApplicationData::Current>LocalFolder,"test.dat");
    
	    byte * data = new byte[KB]; 
	    for (int i=0; i<KB; i++) data[i]='1';

	    Platform::Array<byte>^ tempfileData = ref new   
         Platform::Array<byte>(m_blocksize);
	
     for (int i=0; i<m_blocksize/KB; i++)
	    {
        memcpy(tempfileData->Data + i*KB, data, KB);
	    }

	    BasicTimer^ deltatime = ref new BasicTimer();
	    for (long i=0; i< m_filesize/m_blocksize; i++)
	    {
	        pfileReaderWriter->Write(tempfileData, 
                                  tempfileData->Length);
     }
	    deltatime->Update();
	    m_deltatime = deltatime->Delta;

	    OutputTextBlock->Text = "The file is written with size " 
          +(pfileReaderWriter->GetFileSize()).ToString() 
		+ ". UI thread block time is " + m_deltatime.ToString() 
          + " seconds.";
}

Sample Code 2. Sequentially write to file with a fixed block size **

2.2.2 Random Read/Write

Windows* Runtime supports API to move the file pointer of a specified file. The API is SetFilePointerEx. The basic file read/write class FileAccessReader in our code example has a method SeekAbsolute to call this API in order to set the offset of the file pointer. With this method, we can implement the random read/write.

The sample code 3 shows the implementation of random reads in our case study.

void RandomReadFileButton_Click(Object^ sender, 
                                RoutedEventArgs^ e)
{

FileAccessReader^ pfileReaderWriter = ref new 
    FileAccessReader(ApplicationData::Current->LocalFolder,     
    "test.dat");

	   Platform::Array<byte>^ tempfileData = ref new 
          Platform::Array<byte>(m_blocksize);

	   std:srand(time(NULL));
	   long long offset;
	   BasicTimer^ deltatime = ref new BasicTimer();
	   for (long i=0; i< m_filesize/m_blocksize; i++)
	   {
          // seek a random offset in the file for read
		offset = std::rand();
		offset = ((offset % 100)/ 100.0) * m_filesize; 
		offset -= (offset % m_blocksize);
		pfileReaderWriter->SeekAbsolute(offset);
         // read a block with fixed length from the file
		tempfileData = pfileReaderWriter->Read(
                                 tempfileData->Length);
	   }
	   deltatime->Update();
	   m_deltatime = deltatime->Delta;
			
OutputTextBlock->Text = "File content to position " 
  + (pfileReaderWriter->GetPosition()).ToString()
  + ". UI thread block time is " + m_deltatime.ToString() 
  + " seconds.";
}

Sample Code 3. Random read from a file with a fixed block size **

The sample code 4 shows the implementation of random writes in our case study.

void RandomWriteFileButton_Click(Object^ sender, 
                                 RoutedEventArgs^ e)
{
	    
RandomAccessReader^ pfileReaderWriter = 
        ref new RandomAccessReader(
           ApplicationData::Current->LocalFolder,"test.dat");

	   byte * data = new byte[KB]; 
	   for (int i=0; i<KB; i++) data[i]='1';
	
	   Platform::Array<byte>^ tempfileData = ref new     
                             Platform::Array<byte>(m_blocksize);
    // Fill in a block with size(=m_blocksize) with all data ‘1’s
	   for (int i=0; i<m_blocksize/KB; i++)
	   {
        memcpy(tempfileData->Data + i*KB, data, KB);
	   }
	   std:srand(time(NULL));
	
	   BasicTimer^ deltatime = ref new BasicTimer();
	   for (long i=0; i< m_filesize/m_blocksize; i++)
	   {
        // seek a random offset in the file for write
	       offset = std::rand();
	       offset = ((offset % 100)/ 100.0) * m_filesize; 
	       offset -= (offset % m_blocksize);
	       pfileReaderWriter->SeekAbsolute(offset);
        // Write a block with fixed length to the file
	       pfileReaderWriter->Write(tempfileData, 
                                 tempfileData->Length);
 	    }
	    deltatime->Update();
	    m_deltatime = deltatime->Delta;
		
     OutputTextBlock->Text = "The file is written with size " 
           + (pfileReaderWriter->GetFileSize()).ToString() 
           + ". UI thread block time is " 
           + m_deltatime.ToString() + " seconds.";
}

Sample Code 4. Random write to a file with a fixed block size **

2.3 Read/Write Block Size Impact

We implement the sequential/random read/write in a Windows store app to read and write with various block sizes from/to a 1GB file on eMMC in a tablet. We compare the platform power consumption and the completion time for the reads and writes.



Figure 1: Comparison of the platform power and the completion time for Read/Write with different block sizes

Figure 1 plots the average platform power consumption relative to the system idle power and the completion time in seconds. The bars represents the completion time for reading/writing the 1GB file. The lines represent the average relative platform power. As we can see, the read/write with small block sizes like 4KB consumes more power and takes significantly longer to complete than the ones with large block sizes like 64KB and 128KB. Therefore, the read/write with small block sizes consumes more energy, which is calculated by the platform power multiplying the completion time. One tip for app developers is to buffer small read/write to big block size. This can improve the read/write performance and also consumes less power, thereby saving energy for the applications.

3. Network Transfer Impact

In this session, we have a case study on Windows runtime API usage for network transfer impact on energy efficiency.

3.1 Network Device

Many mobile apps utilize Wifi for network communication with remote servers. The representative applications are web browsing apps, news apps, online gaming apps and online reader apps etc. Wifi device is widely utilized as it is the fastest way to transfer data with low cost. Wifi device usage is managed by the device driver and the embedded controller on the device. It has power saving states to reduce power consumption when idle. Some Wifi devices have advanced power saving features to enter different power states depending on the Wifi data transfer rate.

Many Wifi based apps need communicate with remote servers for data transfer. Before the data transfer, compression can be utilized to reduce the data size. We have a case study on whether mobile apps should compress data before transfer through Wifi in a Windows* Store app.

3.2 Network Transfer and Data Compression

Windows* Runtime provides Windows::Networking::BackgroundTransfer namespace to support back ground network transfer like uploading to and downloading from a remote server.

The sample code 5 shows how to configure a background task to download files from a remote server. Note that the background download APIs should be called from a task as it is an asynchronous action and will not block the UI.

BackgroundDownloader^ downloader = ref new BackgroundDownloader();DownloadOperation^
download = downloader
                       ->CreateDownload(source, destinationFile); 
 
// Attach progress and completion handlers. 
HandleDownloadAsync(download, true); 

Sample Code 5. Enable the background download in a task **

The sample code 6 shows how to configure a background task to upload files to a remote server. Note that the background upload APIs should be called from a task as it is an asynchronous action and will not block the UI.

BackgroundUploader^ uploader = ref new BackgroundUploader(); 
uploader->SetRequestHeader("Filename", file->Name); 
 
UploadOperation^ upload = uploader->CreateUpload(uri, file); 
// Attach progress and completion handlers. 
HandleUploadAsync(upload, true); 

Sample Code 6. Enable the background upload in a task **

Windows* Runtime provides Windows::Storage::Compression namespace to support data compression and decompression. Compressor and Decompressor classes are supported with five different compression/decompression options. One is no compression and the others are Mszip, Xpress, Xpresshuff and Lzms algorithms. Please refer to the detail descriptions for the usage of the algorithms. These compression/decompression options can be utilized for the data processing before network transfer.

3.3 UI Thread Frame Rate and Power Comparison

We implement the compression/decompression and the uploading/downloading files to/from a remote server with Windows* Runtime APIs in a Windows* store app. We consider both highly compressible data and less compressible data. We compare the completion time for uploading/downloading and compression/decompression. We also compare the average platform power consumption for the durations.

3.3.1 Highly Compressible Data

We utilize a set of highly compressible data like csv data files etc. The data sizes after compression are around 30%. The detailed data sizes after compression are as follows.

AlgorithmNo compressionLZMSMSZIPXpressXpress-Huff

Compressed Data Size

100%

20%

22%

39%

30%

Figure 2 plots the average platform power relative to system idle power and the completion time of uploading/downloading and data compression/decompression.



Figure 2: Comparison of the platform power, the completion time and the energy consumption for network transfer with highly compressible data

From the lines representing the average platform power, the power consumption for all the cases is about the same. This implies that the data compression/ decompression do not introduce significant power increase. From the bars representing the completion time, the no-compression case takes significant longer time than the other cases with data compression. The energy consumption for all the cases is plotted in the bottom of the figure. The no-compression case consumes more energy than all the other cases. This means, for highly compressible data, compression helps to save energy and improves performance with negligible power cost. We recommend app developers consider using compression for highly compressible data in network transfer apps.

3.3.2 Less Compressible Data

We utilize a set of less compressible data like PNG image data files etc. The data sizes after compression are around 80%. The detailed data sizes after compression are as follows.

AlgorithmNo compression

LZMSMSZIPXpressXpress-Huff

Compressed Data Size

100%

82%

82%

84%

84%

Figure 3 plots the average platform power relative to system idle power and the completion time of uploading/downloading and data compression/decompression.



Figure 3: Comparison of the platform power, the completion time and the energy consumption for network transfer with less compressible data

From the lines representing the average platform power, the power consumption for all the cases is about the same. From the bars representing the completion time, the no-compression case takes slightly longer time than the other cases with data compression. The energy consumptions for all the cases are plotted in the bottom of the figure. The no-compression case consumes slightly more energy than all the other cases. This means that the compression has less benefit for energy efficiency. On the other hand, the data compression/ decompression algorithms introduce minimal power and performance overheads. Though the energy efficiency benefit of compressions is small, compression has minimal harm on energy savings. We still recommend app developers consider using compression for less compressible data in network transfer apps.

4. Sensor Usage Impact

4.1 Sensors

There are a large variety of sensors embedded in mobile platforms, like accelerometer, gyroscope, compass, geo-location based sensors etc. These sensors enter low power state when no data are requested from the sensors.

Many mobile apps utilize various sensors for better user interaction or app intelligence. Generally UI updates in these apps opt to be triggered by the sensor data changes. In Windows* Store apps, apps can register the sensors and have two kinds of implementations to access sensor data. One is event driven mode. Apps can register data changes with a minimal report interval setting. Whenever the sensor data change happens, the registered app is notified with the sensor data. The other one is polling mode. Apps can set a periodic timer to request the sensor data.

From the power perspective, we have a case study on accelerometer with the two implementations for accessing data in a Windows* Store app.

4.2 Accelerometer

Windows Runtime provides Windows.Devices.Sensors.Accelerometer class in order to access the accelerometer data. Here are the code examples for the event driven mode and the polling mode.

The sample code 7 shows how to instantiate an accelerometer and set the minimal report interval for the app getting notified.

accelerometer = Accelerometer::GetDefault();
if (accelerometer != nullptr)
{
    // Detect the supported minimum report interval
uint32 minReportInterval = 
               accelerometer->MinimumReportInterval;
// Set the desired report interval
Accelerometer.reportInterval = 
          minReportInterval > 16 ? minReportInterval : 16;
}

Sample Code 7. Set the minimum report interval of accelerometer **

The sample code 8 shows how to access the accelerometer data with event driven mode.

// Enable accelerometer
listenerToken = accelerometer->ReadingChanged::add(
               ref new TypedEventHandler<Accelerometer^, 
               AccelerometerReadingChangedEventArgs^>(this, 
               &ReadingChanged));

// Accelerometer data change handler
void ReadingChanged(Accelerometer^ sender, 
                    AccelerometerReadingChangedEventArgs^ e)
{
    // Dispatch to UI thread to display the output
    auto ignored = Dispatcher->RunAsync(
                     CoreDispatcherPriority::Normal,
                     ref new DispatchedHandler([this, e]()
    {
        AccelerometerReading^ reading = e->Reading;
        Output_X->Text = reading->AccelerationX.ToString();
        Output_Y->Text = reading->AccelerationY.ToString();
        Output_Z->Text = reading->AccelerationZ.ToString();
	   },
    CallbackContext::Any));
}

Sample Code 8. Access the accelerometer data with event driven mode **

The sample code 9 shows how to access the accelerometer data with polling mode.

// Set up a periodic timer for polling the accelerometer data
accelerometer = Accelerometer::GetDefault();
if (accelerometer != nullptr)
{
    // Detect the supported minimum report interval
uint32 minReportInterval = accelerometer
                              ->MinimumReportInterval;
desiredReportInterval = minReportInterval > 16 
                            ? minReportInterval : 16;

    // Set up a DispatchTimer
TimeSpan span; 
    
    span.Duration = static_cast<int32>(
        desiredReportInterval) * 10000; // convert to 100ns ticks
    dispatcherTimer = ref new DispatcherTimer();
    dispatcherTimer->Interval = span;
dispatcherTimer->Tick += ref new 
          Windows::Foundation::EventHandler<Object^>(this, 
          &DisplayCurrentReading);
}
// Accelerometer data polling handler
void DisplayCurrentReading(Object^ sender, Object^ e)
{
AccelerometerReading^ reading = 
                    accelerometer->GetCurrentReading();
    if (reading != nullptr)
    {
        Output_X->Text = reading->AccelerationX.ToString();
        Output_Y->Text = reading->AccelerationY.ToString();
        Output_Z->Text = reading->AccelerationZ.ToString();
    }
}

Sample Code 9. Access the accelerometer data with polling mode **

4.3 Power Impact

We consider two scenarios with the two implementation modes. One scenario is to put the device on a stationary table. The other is to hold the device in hand without movement. We set different minimal report intervals or polling periods for the two implementations. We compare the average platform power relative to system idle power.

Figure 4 plots the power comparison for different scenarios with the two implementations. At a particular minimal report interval setting like 16ms, the platform consumes less power for the event-driven mode when the device is on a stationary table. This is because there is no significant accelerometer data change when the device is on a stationary table. When the device is held in hand without movement, the platform power consumption is close to the ones with polling mode. This is because the accelerometer is sensitive enough to have frequent data change when the device is held in hand. In order to save power, we recommend app developers use event driven implementation to access sensor data and be careful to use data change to drive UI changes.



Figure 4: Comparison of the platform power for two implementations to access accelerometer data

5. Summary

In the article we discuss hardware components like storage, Wifi and sensors. We address the file access, network transfer and sensor usage applications. Then we discuss how to save the platform power in a Windows* Store app. We expect developers can apply this guideline in the software development cycle.

6. About the Author

Sushu Zhang is a software engineer in Intel's Software and Services Group. She is working on ISV scale enabling for Intel-based platforms with Android* / Windows OS. She developed the Intel® Power Monitoring Tool for Android Devices. Most recently, Sushu has been involved with several energy-efficiency projects at Intel. Prior to joining Intel, Sushu worked at Microsoft on Windows energy efficiency. Sushu earned a Ph.D in Computer Science at the Arizona State University. Her research area was system-level power and thermal management.

Notices

**This sample source code is released under the Intel OBL Sample Source Code License (MS-LPL Compatible) and Microsoft Limited Public License. Copyright© 2012 Intel Corporation. All rights reserved.

Performance Notice

For more complete information about performance and benchmark results, visit www.intel.com/benchmarks

Para obter informações mais completas sobre otimizações do compilador, consulte nosso aviso de otimização.