int32_t GCConfigTest::triggerOperation(pugi::xml_node node) { OMRPORT_ACCESS_FROM_OMRPORT(gcTestEnv->portLib); int32_t rt = 0; for (; node; node = node.next_sibling()) { if (0 == strcmp(node.name(), "systemCollect")) { const char *gcCodeStr = node.attribute("gcCode").value(); if (0 == strcmp(gcCodeStr, "")) { /* gcCode defaults to J9MMCONSTANT_IMPLICIT_GC_DEFAULT */ gcCodeStr = "0"; } uint32_t gcCode = (uint32_t)atoi(gcCodeStr); omrtty_printf("Invoking gc system collect with gcCode %d...\n", gcCode); rt = (int32_t)OMR_GC_SystemCollect(exampleVM->_omrVMThread, gcCode); if (OMR_ERROR_NONE != rt) { omrtty_printf("%s:%d Failed to perform OMR_GC_SystemCollect with error code %d.\n", __FILE__, __LINE__, rt); goto done; } OMRGCTEST_CHECK_RT(rt); verboseManager->getWriterChain()->endOfCycle(env); } } done: return rt; }
int32_t GCConfigTest::insertGarbage() { OMRPORT_ACCESS_FROM_OMRVM(exampleVM->_omrVM); int32_t rt = 0; char fullNamePrefix[MAX_NAME_LENGTH]; omrstr_printf(fullNamePrefix, sizeof(fullNamePrefix), "%s_%d", gp.namePrefix, gp.garbageSeq++); int32_t breadth = 2; uintptr_t totalSize = (uintptr_t)(gp.accumulatedSize * gp.percentage) / 100; uintptr_t objSize = 0; if (0 == strcmp(gp.structure, "node")) { objSize = totalSize; } else if (0 == strcmp(gp.structure, "tree")) { objSize = 64; } #if defined(OMRGCTEST_DEBUG) omrtty_printf("Inserting garbage %s of %dB (%f%% of previous object/tree size %dB) ...\n", fullNamePrefix, totalSize, gp.percentage, gp.accumulatedSize); #endif omrobjectptr_t rootObj = NULL; rt = createFixedSizeTree(&rootObj, fullNamePrefix, GARBAGE_ROOT, totalSize, objSize, breadth); OMRGCTEST_CHECK_RT(rt); /* remove garbage root object from the root set */ if (NULL != rootObj) { char rootObjName[MAX_NAME_LENGTH]; omrstr_printf(rootObjName, MAX_NAME_LENGTH, "%s_%d_%d", fullNamePrefix, 0, 0); rt = removeObjectFromRootTable(rootObjName); OMRGCTEST_CHECK_RT(rt); } /* reset accumulatedSize */ gp.accumulatedSize = 0; done: return rt; }
int32_t GCConfigTest::createObject(omrobjectptr_t *obj, char **objName, const char *namePrefix, OMRGCObjectType objType, int32_t depth, int32_t nthInRow, uintptr_t size) { OMRPORT_ACCESS_FROM_OMRPORT(gcTestEnv->portLib); int32_t rt = 0; ObjectEntry *objEntry = NULL; *objName = (char *)omrmem_allocate_memory(MAX_NAME_LENGTH, OMRMEM_CATEGORY_MM); if (NULL == *objName) { rt = 1; omrtty_printf("%s:%d Failed to allocate native memory.\n", __FILE__, __LINE__); goto done; } omrstr_printf(*objName, MAX_NAME_LENGTH, "%s_%d_%d", namePrefix, depth, nthInRow); if (0 == objectTable.find(&objEntry, *objName)) { #if defined(OMRGCTEST_DEBUG) omrtty_printf("Find object %s in hash table.\n", *objName); #endif *obj = objEntry->objPtr; } else { rt = allocateHelper(obj, *objName, size); OMRGCTEST_CHECK_RT(rt); /* keep object in table */ rt = objectTable.add(*objName, *obj, 0); OMRGCTEST_CHECK_RT(rt) /* Keep count of the new allocated non-garbage object size for garbage insertion. If the object exists in objectTable, its size is ignored. */ if ((ROOT == objType) || (NORMAL == objType)) { gp.accumulatedSize += env->getExtensions()->objectModel.getSizeInBytesWithHeader(*obj); } } done: return rt; }
int32_t GCConfigTest::allocationWalker(pugi::xml_node node) { OMRPORT_ACCESS_FROM_OMRVM(exampleVM->_omrVM); int32_t rt = 0; AttributeElem *numOfFieldsElem = NULL; AttributeElem *breadthElem = NULL; int32_t depth = 0; OMRGCObjectType objType = INVALID; const char *namePrefixStr = node.attribute("namePrefix").value(); const char *numOfFieldsStr = node.attribute("numOfFields").value(); const char *typeStr = node.attribute("type").value(); const char *breadthStr = node.attribute("breadth").value(); const char *depthStr = node.attribute("depth").value(); if (0 != strcmp(node.name(), "object")) { /* allow non-object node nested inside allocation? */ goto done; } if ((0 == strcmp(namePrefixStr, "")) || (0 == strcmp(typeStr, "")) || (0 == strcmp(numOfFieldsStr, ""))) { rt = 1; omrtty_printf("%s:%d Invalid XML input: please specify namePrefix, type and numOfFields for object %s.\n", __FILE__, __LINE__, namePrefixStr); goto done; } /* set default value for breadth and depth to 1 */ if (0 == strcmp(breadthStr, "")) { breadthStr = "1"; } if (0 == strcmp(depthStr, "")) { depthStr = "1"; } depth = atoi(depthStr); objType = parseObjectType(node); rt = parseAttribute(&numOfFieldsElem, numOfFieldsStr); OMRGCTEST_CHECK_RT(rt) rt = parseAttribute(&breadthElem, breadthStr); OMRGCTEST_CHECK_RT(rt); /* process current xml node, perform allocation for single object or object tree */ rt = processObjNode(node, namePrefixStr, objType, numOfFieldsElem, breadthElem, depth); OMRGCTEST_CHECK_RT(rt); /* only single object can contain nested child object */ if ((0 == strcmp(breadthStr, "1")) && (0 == strcmp(depthStr, "1"))) { for (pugi::xml_node childNode = node.first_child(); childNode; childNode = childNode.next_sibling()) { rt = allocationWalker(childNode); OMRGCTEST_CHECK_RT(rt); } } /* After the entire garbage tree is allocated, remove garbage root object from the root set * or remove garbage top object from the slot of its parent object. */ if (GARBAGE_ROOT == objType) { for (int32_t i = 0; i < breadthElem->value; i++) { char objName[MAX_NAME_LENGTH]; omrstr_printf(objName, MAX_NAME_LENGTH, "%s_%d_%d", namePrefixStr, 0, i); rt = removeObjectFromRootTable(objName); OMRGCTEST_CHECK_RT(rt); } } else if (GARBAGE_TOP == objType) { char parentName[MAX_NAME_LENGTH]; omrstr_printf(parentName, MAX_NAME_LENGTH, "%s_%d_%d", node.parent().attribute("namePrefix").value(), 0, 0); ObjectEntry *parentEntry; rt = objectTable.find(&parentEntry, parentName); if (0 != rt) { omrtty_printf("%s:%d Could not find object %s in hash table.\n", __FILE__, __LINE__, parentName); goto done; } omrobjectptr_t parentPtr = parentEntry->objPtr; for (int32_t i = 0; i < breadthElem->value; i++) { char objName[MAX_NAME_LENGTH]; omrstr_printf(objName, MAX_NAME_LENGTH, "%s_%d_%d", namePrefixStr, 0, i); rt = removeObjectFromParentSlot(objName, parentPtr); OMRGCTEST_CHECK_RT(rt); } } /* insert garbage per tree */ if ((0 == strcmp(gp.frequency, "perRootStruct")) && (ROOT == objType)){ rt = insertGarbage(); OMRGCTEST_CHECK_RT(rt); } done: freeAttributeList(breadthElem); freeAttributeList(numOfFieldsElem); return rt; }
int32_t GCConfigTest::processObjNode(pugi::xml_node node, const char *namePrefixStr, OMRGCObjectType objType, AttributeElem *numOfFieldsElem, AttributeElem *breadthElem, int32_t depth) { OMRPORT_ACCESS_FROM_OMRPORT(gcTestEnv->portLib); int32_t rt = 0; OMR_VM *omrVMPtr = exampleVM->_omrVM; int32_t numOfParents = 0; /* Create objects and store them in the root table or the slot object based on objType. */ if ((ROOT == objType) || (GARBAGE_ROOT == objType)) { for (int32_t i = 0; i < breadthElem->value; i++) { omrobjectptr_t obj; char *objName = NULL; uintptr_t sizeCalculated = numOfFieldsElem->value * sizeof(fomrobject_t) + sizeof(uintptr_t); rt = createObject(&obj, &objName, namePrefixStr, objType, 0, i, sizeCalculated); OMRGCTEST_CHECK_RT(rt); numOfFieldsElem = numOfFieldsElem->linkNext; /* Add object to root hash table. If it's the root of the garbage tree, temporarily keep it as root for allocating * the rest of the tree. Remove it from the root set after the entire garbage tree is allocated.*/ RootEntry rEntry; rEntry.name = objName; rEntry.rootPtr = obj; if (NULL == hashTableAdd(exampleVM->rootTable, &rEntry)) { rt = 1; omrtty_printf("%s:%d Failed to add new root entry to root table!\n", __FILE__, __LINE__); goto done; } /* insert garbage per node */ if ((ROOT == objType) && (0 == strcmp(gp.frequency, "perObject"))) { rt = insertGarbage(); OMRGCTEST_CHECK_RT(rt); } } } else if ((NORMAL == objType) || (GARBAGE_TOP == objType) || (GARBAGE_CHILD == objType)) { char parentName[MAX_NAME_LENGTH]; omrstr_printf(parentName, MAX_NAME_LENGTH, "%s_%d_%d", node.parent().attribute("namePrefix").value(), 0, 0); ObjectEntry *parentEntry; rt = objectTable.find(&parentEntry, parentName); if (0 != rt) { omrtty_printf("%s:%d Could not find object %s in hash table.\n", __FILE__, __LINE__, parentName); goto done; } omrobjectptr_t parent = parentEntry->objPtr; GC_ObjectIterator objectIterator(omrVMPtr, parent); objectIterator.restore(parentEntry->numOfRef); for (int32_t i = 0; i < breadthElem->value; i++) { omrobjectptr_t obj; char *objName = NULL; uintptr_t sizeCalculated = numOfFieldsElem->value * sizeof(fomrobject_t) + sizeof(uintptr_t); rt = createObject(&obj, &objName, namePrefixStr, objType, 0, i, sizeCalculated); OMRGCTEST_CHECK_RT(rt); numOfFieldsElem = numOfFieldsElem->linkNext; GC_SlotObject *slotObject = NULL; if (NULL != (slotObject = objectIterator.nextSlot())) { #if defined(OMRGCTEST_DEBUG) omrtty_printf("\tadd to slot of parent(%llu) %d\n", parent, parentEntry->numOfRef + i); #endif /* Add object to parent's slot. If it's the top of the garbage tree, temporarily keep it in the slot until * the rest of the tree is allocated. */ slotObject->writeReferenceToSlot(obj); } else { rt = 1; omrtty_printf("%s:%d Invalid XML input: numOfFields defined for %s is not enough to hold all children references.\n", __FILE__, __LINE__, parentName); goto done; } /* insert garbage per node */ if ((NORMAL == objType) && (0 == strcmp(gp.frequency, "perObject"))) { rt = insertGarbage(); OMRGCTEST_CHECK_RT(rt); } } parentEntry->numOfRef += breadthElem->value; } else { rt = 1; goto done; } /* Create the rest of the tree, if any, defined with depth. First, we set the child object with correct objType. */ if (ROOT == objType) { objType = NORMAL; } else if ((GARBAGE_TOP == objType) || (GARBAGE_ROOT == objType)) { objType = GARBAGE_CHILD; } numOfParents = breadthElem->value; breadthElem = breadthElem->linkNext; for (int32_t i = 1; i < depth; i++) { int32_t nthInRow = 0; for (int32_t j = 0; j < numOfParents; j++) { char parentName[MAX_NAME_LENGTH]; omrstr_printf(parentName, sizeof(parentName), "%s_%d_%d", namePrefixStr, (i - 1), j); ObjectEntry *parentEntry; rt = objectTable.find(&parentEntry, parentName); if (0 != rt) { omrtty_printf("%s:%d Could not find object %s in hash table.\n", __FILE__, __LINE__, parentName); goto done; } omrobjectptr_t parent = parentEntry->objPtr; GC_ObjectIterator objectIterator(omrVMPtr, parent); objectIterator.restore(parentEntry->numOfRef); for (int32_t k = 0; k < breadthElem->value; k++) { omrobjectptr_t obj; char *objName = NULL; uintptr_t sizeCalculated = numOfFieldsElem->value * sizeof(fomrobject_t) + sizeof(uintptr_t); rt = createObject(&obj, &objName, namePrefixStr, objType, i, nthInRow, sizeCalculated); OMRGCTEST_CHECK_RT(rt); numOfFieldsElem = numOfFieldsElem->linkNext; nthInRow += 1; GC_SlotObject *slotObject = NULL; if (NULL != (slotObject = objectIterator.nextSlot())) { #if defined(OMRGCTEST_DEBUG) omrtty_printf("\tadd to parent(%llu) slot %d.\n", parent, parentEntry->numOfRef + k); #endif slotObject->writeReferenceToSlot(obj); } else { rt = 1; omrtty_printf("%s:%d Invalid XML input: numOfFields defined for %s is not enough to hold all children references.\n", __FILE__, __LINE__, parentName); goto done; } /* insert garbage per node */ if ((NORMAL == objType) && (0 == strcmp(gp.frequency, "perObject"))) { rt = insertGarbage(); OMRGCTEST_CHECK_RT(rt); } } parentEntry->numOfRef += breadthElem->value; } numOfParents = nthInRow; breadthElem = breadthElem->linkNext; } done: return rt; }
int32_t GCConfigTest::createFixedSizeTree(omrobjectptr_t *rootObj, const char *namePrefixStr, OMRGCObjectType objType, uintptr_t totalSize, uintptr_t objSize, int32_t breadth) { OMRPORT_ACCESS_FROM_OMRPORT(gcTestEnv->portLib); int32_t rt = 0; OMR_VM *omrVMPtr = exampleVM->_omrVM; int32_t depth = 1; int32_t numOfParents = 1; uintptr_t bytesLeft = totalSize; if (bytesLeft < objSize) { objSize = bytesLeft; if (objSize <= 0) { return rt; } } /* allocate the root object */ char *rootObjName = NULL; rt = createObject(rootObj, &rootObjName, namePrefixStr, objType, 0, 0, objSize); OMRGCTEST_CHECK_RT(rt); bytesLeft -= objSize; /* Add object to root hash table. If it's the root of the garbage tree, temporarily keep it as root for allocating * the rest of the tree. Remove it from the root set after the entire garbage tree is allocated.*/ RootEntry rEntry; rEntry.name = rootObjName; rEntry.rootPtr = *rootObj; if (NULL == hashTableAdd(exampleVM->rootTable, &rEntry)) { rt = 1; omrtty_printf("%s:%d Failed to add new root entry to root table!\n", __FILE__, __LINE__); goto done; } /* create the rest of the tree */ if (ROOT == objType) { objType = NORMAL; } else if ((GARBAGE_TOP == objType) || (GARBAGE_ROOT == objType)) { objType = GARBAGE_CHILD; } while (bytesLeft > 0) { int32_t nthInRow = 0; for (int32_t j = 0; j < numOfParents; j++) { char parentName[MAX_NAME_LENGTH]; omrstr_printf(parentName, sizeof(parentName), "%s_%d_%d", namePrefixStr, (depth - 1), j); ObjectEntry *parentEntry; rt = objectTable.find(&parentEntry, parentName); if (0 != rt) { omrtty_printf("%s:%d Could not find object %s in hash table.\n", __FILE__, __LINE__, parentName); goto done; } omrobjectptr_t parent = parentEntry->objPtr; GC_ObjectIterator objectIterator(omrVMPtr, parent); objectIterator.restore(parentEntry->numOfRef); for (int32_t k = 0; k < breadth; k++) { if (bytesLeft < objSize) { objSize = bytesLeft; if (objSize <= 0) { goto done; } } omrobjectptr_t obj; char *objName = NULL; rt = createObject(&obj, &objName, namePrefixStr, objType, depth, nthInRow, objSize); OMRGCTEST_CHECK_RT(rt); bytesLeft -= objSize; nthInRow += 1; GC_SlotObject *slotObject = NULL; if (NULL != (slotObject = objectIterator.nextSlot())) { #if defined(OMRGCTEST_DEBUG) omrtty_printf("\tadd to parent(%llu) slot %d.\n", parent, parentEntry->numOfRef + k); #endif slotObject->writeReferenceToSlot(obj); } else { rt = 1; omrtty_printf("%s:%d Invalid XML input: numOfFields defined for %s is not enough to hold all children references.\n", __FILE__, __LINE__, parentName); goto done; } } parentEntry->numOfRef += breadth; } numOfParents = nthInRow; depth += 1; } done: return rt; }
int32_t GCConfigTest::processObjNode(pugi::xml_node node, const char *namePrefixStr, OMRGCObjectType objType, AttributeElem *numOfFieldsElem, AttributeElem *breadthElem, int32_t depth) { OMRPORT_ACCESS_FROM_OMRPORT(gcTestEnv->portLib); int32_t rt = 1; int32_t numOfParents = 0; /* Create objects and store them in the root table or the slot object based on objType. */ if ((ROOT == objType) || (GARBAGE_ROOT == objType)) { for (int32_t i = 0; i < breadthElem->value; i++) { uintptr_t sizeCalculated = numOfFieldsElem->value * sizeof(fomrobject_t) + sizeof(uintptr_t); ObjectEntry *objectEntry = createObject(namePrefixStr, objType, 0, i, sizeCalculated); if (NULL == objectEntry) { goto done; } numOfFieldsElem = numOfFieldsElem->linkNext; /* Add object to root hash table. If it's the root of the garbage tree, temporarily keep it as root for allocating * the rest of the tree. Remove it from the root set after the entire garbage tree is allocated.*/ RootEntry rEntry; rEntry.name = objectEntry->name; rEntry.rootPtr = objectEntry->objPtr; if (NULL == hashTableAdd(exampleVM->rootTable, &rEntry)) { omrtty_printf("%s:%d Failed to add new root entry to root table!\n", __FILE__, __LINE__); goto done; } /* insert garbage per node */ if ((ROOT == objType) && (0 == strcmp(gp.frequency, "perObject"))) { int32_t grt = insertGarbage(); OMRGCTEST_CHECK_RT(grt); } } } else if ((NORMAL == objType) || (GARBAGE_TOP == objType) || (GARBAGE_CHILD == objType)) { char parentName[MAX_NAME_LENGTH]; omrstr_printf(parentName, MAX_NAME_LENGTH, "%s_%d_%d", node.parent().attribute("namePrefix").value(), 0, 0); for (int32_t i = 0; i < breadthElem->value; i++) { uintptr_t sizeCalculated = numOfFieldsElem->value * sizeof(fomrobject_t) + sizeof(uintptr_t); ObjectEntry *childEntry = createObject(namePrefixStr, objType, 0, i, sizeCalculated); if (NULL == childEntry) { goto done; } ObjectEntry *parentEntry = find(parentName); if (NULL == parentEntry) { omrtty_printf("%s:%d Could not find object %s in hash table.\n", __FILE__, __LINE__, parentName); goto done; } if (0 != attachChildEntry(parentEntry, childEntry)) { goto done; } numOfFieldsElem = numOfFieldsElem->linkNext; /* insert garbage per node */ if ((NORMAL == objType) && (0 == strcmp(gp.frequency, "perObject"))) { int32_t grt = insertGarbage(); OMRGCTEST_CHECK_RT(grt); } } } else { goto done; } /* Create the rest of the tree, if any, defined with depth. First, we set the child object with correct objType. */ if (ROOT == objType) { objType = NORMAL; } else if ((GARBAGE_TOP == objType) || (GARBAGE_ROOT == objType)) { objType = GARBAGE_CHILD; } numOfParents = breadthElem->value; breadthElem = breadthElem->linkNext; for (int32_t i = 1; i < depth; i++) { int32_t nthInRow = 0; for (int32_t j = 0; j < numOfParents; j++) { char parentName[MAX_NAME_LENGTH]; omrstr_printf(parentName, sizeof(parentName), "%s_%d_%d", namePrefixStr, (i - 1), j); for (int32_t k = 0; k < breadthElem->value; k++) { uintptr_t sizeCalculated = sizeof(omrobjectptr_t) + numOfFieldsElem->value * sizeof(fomrobject_t); ObjectEntry *childEntry = createObject(namePrefixStr, objType, i, nthInRow, sizeCalculated); if (NULL == childEntry) { goto done; } ObjectEntry *parentEntry = find(parentName); if (NULL == parentEntry) { omrtty_printf("%s:%d Could not find object %s in hash table.\n", __FILE__, __LINE__, parentName); goto done; } if (0 != attachChildEntry(parentEntry, childEntry)) { goto done; } numOfFieldsElem = numOfFieldsElem->linkNext; nthInRow += 1; /* insert garbage per node */ if ((NORMAL == objType) && (0 == strcmp(gp.frequency, "perObject"))) { int32_t grt = insertGarbage(); OMRGCTEST_CHECK_RT(grt); } } } numOfParents = nthInRow; breadthElem = breadthElem->linkNext; } rt = 0; done: return rt; }