You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@openwhisk.apache.org by GitBox <gi...@apache.org> on 2018/12/06 10:28:24 UTC

[GitHub] sven-lange-last closed pull request #4155: Make ActionLimits test more reliable

sven-lange-last closed pull request #4155: Make ActionLimits test more reliable
URL: https://github.com/apache/incubator-openwhisk/pull/4155
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/tests/dat/actions/memoryWithGC.js b/tests/dat/actions/memoryWithGC.js
index 35c0a0c068..98db2f0e6c 100644
--- a/tests/dat/actions/memoryWithGC.js
+++ b/tests/dat/actions/memoryWithGC.js
@@ -1,16 +1,91 @@
 // Licensed to the Apache Software Foundation (ASF) under one or more contributor
 // license agreements; and to You under the Apache License, Version 2.0.
 
-function eat(memoryMB) {
-    var bytes = 1*1024*1024*memoryMB;
-    var buffer = new Buffer.alloc(bytes, 'a');
-    buffer = null;
-    console.log('done.');
+'use strict';
+
+// Usually, Linux systems have a page size of 4096 byte
+// The actual value can be obtained with `getconf PAGESIZE`
+const pageSizeInB = 4096;
+
+// This array will be used to store all allocated blocks
+// such that they won't be garbage collected
+let blocks = [];
+
+// Allocates a byte array that has page size
+function allocateMemoryBlock(sizeInB) {
+    return new Uint8Array(sizeInB);
+}
+
+// Returns a random number between 0 (inclusive) and
+// the specified value maxExclusive (exclusive)
+function randomUnsigned(maxExclusive) {
+    return Math.floor(Math.random() * maxExclusive);
+}
+
+// Fills the first 4 bytes of the passed byte array with random
+// numbers
+function fillMemoryPage(byteArray) {
+    for (let i = 0; (i < 4) && (i < pageSizeInB); i++) {
+        byteArray[i] = randomUnsigned(256);
+    }
+}
+
+// Consumes the specified amount of physical memory
+// * The memory is allocated in smaller blocks instead of
+//   allocating one large block of memory to prevent
+//   virtual OOM
+// * Size of allocated blocks is a multiple of page size
+// * The number of allocated blocks has an upper bound
+//   because a reference to each block is stored in an
+//   array. If the number of blocks gets too high, the
+//   resulting array grows so large that its contribution
+//   to memory consumption causes trouble.
+//   For this reason, the block size is adjusted to
+//   limit the number of blocks. The resulting allocation
+//   granularity can cause a slight over-consumption of
+//   memory. That's why the upper limit must be selected
+//   carefully.
+// * Fill randomly to prevent memory deduplication
+function eat(memoryInMiB) {
+    const memoryInB = memoryInMiB * 1024 * 1024;
+    const memoryInPages = Math.ceil(memoryInB / pageSizeInB);
+    console.log('helloEatMemory: memoryInB=' + memoryInB + ', memoryInPages=' + memoryInPages);
+
+    let blockSizeInB = pageSizeInB;
+    let memoryInBlocks = memoryInPages;
+    let pagesPerBlock = 1;
+    const maxBlocks = 8192;
+    if (memoryInPages > maxBlocks) {
+        pagesPerBlock = Math.ceil(memoryInB / (maxBlocks * pageSizeInB));
+        blockSizeInB = pagesPerBlock * pageSizeInB;
+        memoryInBlocks = Math.ceil(memoryInB / blockSizeInB);
+    }
+    console.log('helloEatMemory: pagesPerBlock=' + pagesPerBlock + ', blockSizeInB=' + blockSizeInB + ', memoryInBlocks=' + memoryInBlocks);
+
+    for (let b = 0; b < memoryInBlocks; b++) {
+        let byteArray = allocateMemoryBlock(blockSizeInB);
+        fillMemoryPage(byteArray);
+        blocks.push(byteArray);
+    }
+    console.log('helloEatMemory: blocks.length=' + blocks.length);
 }
 
 function main(msg) {
-    console.log('helloEatMemory', 'memory ' + msg.payload + 'MB');
+    console.log('helloEatMemory: memory ' + msg.payload + 'MB');
     global.gc();
     eat(msg.payload);
+
+    console.log('helloEatMemory: completed allocating memory');
+    console.log(process.memoryUsage());
+
+    // This Node.js code is invoked as Apache OW action
+    // We need to explicitly clear the array such that all
+    // allocated memory gets garbage collected and
+    // we have a "fresh" instance on next invocation
+    // Clean up after ourselves such that the warm container
+    // does not keep memory
+    blocks = [];
+    global.gc();
+
     return {msg: 'OK, buffer of size ' + msg.payload + ' MB has been filled.'};
-}
+}
\ No newline at end of file
diff --git a/tests/src/test/scala/org/apache/openwhisk/core/limits/ActionLimitsTests.scala b/tests/src/test/scala/org/apache/openwhisk/core/limits/ActionLimitsTests.scala
index eb10f6e07b..23523c0982 100644
--- a/tests/src/test/scala/org/apache/openwhisk/core/limits/ActionLimitsTests.scala
+++ b/tests/src/test/scala/org/apache/openwhisk/core/limits/ActionLimitsTests.scala
@@ -451,13 +451,14 @@ class ActionLimitsTests extends TestHelpers with WskTestHelpers with WskActorSys
   it should "be aborted when exceeding its memory limits" in withAssetCleaner(wskprops) { (wp, assetHelper) =>
     val name = "TestNodeJsMemoryExceeding"
     assetHelper.withCleaner(wsk.action, name, confirmDelete = true) {
-      val allowedMemory = 128.megabytes
+      val allowedMemory = MemoryLimit.minMemory
       val actionName = TestUtils.getTestActionFilename("memoryWithGC.js")
       (action, _) =>
         action.create(name, Some(actionName), memory = Some(allowedMemory))
     }
 
-    val run = wsk.action.invoke(name, Map("payload" -> 256.toJson))
+    val payload = MemoryLimit.minMemory.toMB * 2
+    val run = wsk.action.invoke(name, Map("payload" -> payload.toJson))
     withActivation(wsk.activation, run) {
       _.response.result.get.fields("error") shouldBe Messages.memoryExhausted.toJson
     }


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services