Skip to content

Commit

Permalink
Native memory allocation trackers
Browse files Browse the repository at this point in the history
Introduce possibility to track native memory that we allocate.
allow track allocations in global and local contexts, where local contexts
can be context of any granularity.
Update primitive off-heap collections to report memory allocation and
de-allocations.
  • Loading branch information
MishaDemianenko committed Feb 1, 2018
1 parent e42b622 commit 5fb9e78
Show file tree
Hide file tree
Showing 19 changed files with 386 additions and 49 deletions.
@@ -0,0 +1,57 @@
/*
* Copyright (c) 2002-2018 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.memory;

import java.util.concurrent.atomic.LongAdder;

/**
* Global memory tracker that can be used in a global multi threaded context to record
* allocation and de-allocation of native memory.
* @see org.neo4j.memory.MemoryAllocationTracker
* @see MemoryTracker
*/
public class GlobalMemoryTracker implements MemoryTracker, MemoryAllocationTracker
{
private LongAdder longAdder = new LongAdder();

public static final GlobalMemoryTracker INSTANCE = new GlobalMemoryTracker();

private GlobalMemoryTracker()
{
}

@Override
public long usedDirectMemory()
{
return longAdder.sum();
}

@Override
public void allocate( long allocatedBytes )
{
longAdder.add( allocatedBytes );
}

@Override
public void deallocate( long deAllocatedBytes )
{
longAdder.add( -deAllocatedBytes );
}
}
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2002-2018 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.memory;

/**
* Memory allocation tracker that can be used in local context that required
* tracking of memory that is independent from global.
* All allocations/de-allocation reported to this trackers also will be reported to global tracker transparently.
*/
public class LocalMemoryTracker implements MemoryTracker, MemoryAllocationTracker
{
private long allocatedBytes;
private GlobalMemoryTracker globalTracker = GlobalMemoryTracker.INSTANCE;

@Override
public void allocate( long allocatedBytes )
{
globalTracker.allocate( allocatedBytes );
this.allocatedBytes += allocatedBytes;
}

@Override
public void deallocate( long deallocatedBytes )
{
globalTracker.deallocate( deallocatedBytes );
this.allocatedBytes -= deallocatedBytes;
}

/**
* @return number of locally used bytes.
*/
@Override
public long usedDirectMemory()
{
return allocatedBytes;
}
}
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2002-2018 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.memory;

/**
* Memory allocation tracker that tracks bytes allocation and de-allocation
*/
public interface MemoryAllocationTracker
{
/**
* Record allocation of bytes
* @param allocatedBytes number of allocated bytes
*/
void allocate( long allocatedBytes );

/**
* Record de-allocation of bytes
* @param deAllocatedBytes number of de0allocated bytes
*/
void deallocate( long deAllocatedBytes );
}
32 changes: 32 additions & 0 deletions community/common/src/main/java/org/neo4j/memory/MemoryTracker.java
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2002-2018 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.memory;

/**
* Tracker that capable to report number of allocated bytes.
* @see MemoryAllocationTracker
*/
public interface MemoryTracker
{
/**
* @return number of bytes of direct memory that are used
*/
long usedDirectMemory();
}
@@ -0,0 +1,52 @@
/*
* Copyright (c) 2002-2018 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.memory;

import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class GlobalMemoryTrackerTest
{

@Test
public void trackMemoryAllocations()
{
long initialUsedMemory = GlobalMemoryTracker.INSTANCE.usedDirectMemory();
GlobalMemoryTracker.INSTANCE.allocate( 10 );
GlobalMemoryTracker.INSTANCE.allocate( 20 );
GlobalMemoryTracker.INSTANCE.allocate( 40 );
assertEquals( 70, GlobalMemoryTracker.INSTANCE.usedDirectMemory() - initialUsedMemory );
}

@Test
public void trackMemoryDeallocations()
{
long initialUsedMemory = GlobalMemoryTracker.INSTANCE.usedDirectMemory();
GlobalMemoryTracker.INSTANCE.allocate( 100 );
assertEquals( 100, GlobalMemoryTracker.INSTANCE.usedDirectMemory() - initialUsedMemory );

GlobalMemoryTracker.INSTANCE.deallocate( 20 );
assertEquals( 80, GlobalMemoryTracker.INSTANCE.usedDirectMemory() - initialUsedMemory );

GlobalMemoryTracker.INSTANCE.deallocate( 40 );
assertEquals( 40, GlobalMemoryTracker.INSTANCE.usedDirectMemory() - initialUsedMemory );
}
}
@@ -0,0 +1,68 @@
/*
* Copyright (c) 2002-2018 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.memory;

import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class LocalMemoryTrackerTest
{
@Test
public void trackMemoryAllocations()
{
LocalMemoryTracker memoryTracker = new LocalMemoryTracker();
memoryTracker.allocate( 10 );
memoryTracker.allocate( 20 );
memoryTracker.allocate( 40 );
assertEquals( 70, memoryTracker.usedDirectMemory());
}

@Test
public void trackMemoryDeallocations()
{
LocalMemoryTracker memoryTracker = new LocalMemoryTracker();
memoryTracker.allocate( 100 );
assertEquals( 100, memoryTracker.usedDirectMemory() );

memoryTracker.deallocate( 20 );
assertEquals( 80, memoryTracker.usedDirectMemory() );

memoryTracker.deallocate( 40 );
assertEquals( 40, memoryTracker.usedDirectMemory() );
}

@Test
public void localMemoryTrackerPropagatesAllocationsToGlobalTracker()
{
GlobalMemoryTracker globalMemoryTracker = GlobalMemoryTracker.INSTANCE;
long initialGlobalUsage = globalMemoryTracker.usedDirectMemory();
LocalMemoryTracker memoryTracker = new LocalMemoryTracker();

memoryTracker.allocate( 100 );
assertEquals( 100, memoryTracker.usedDirectMemory() );
assertEquals( 100, globalMemoryTracker.usedDirectMemory() - initialGlobalUsage );

memoryTracker.deallocate( 50 );
assertEquals( 50, memoryTracker.usedDirectMemory() );
assertEquals( 50, globalMemoryTracker.usedDirectMemory() - initialGlobalUsage );
}

}
Expand Up @@ -23,6 +23,7 @@

import org.neo4j.collection.primitive.Primitive;
import org.neo4j.collection.primitive.PrimitiveLongLongMap;
import org.neo4j.memory.GlobalMemoryTracker;

import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
Expand All @@ -40,7 +41,7 @@ public class ResourceTypesIT
public void indexEntryHashing()
{
int collisions = 0;
try ( PrimitiveLongLongMap map = Primitive.offHeapLongLongMap( 35_000_000 ) )
try ( PrimitiveLongLongMap map = Primitive.offHeapLongLongMap( 35_000_000, GlobalMemoryTracker.INSTANCE ) )
{

int labelIdCount = 50;
Expand Down
Expand Up @@ -19,14 +19,15 @@
*/
package org.neo4j.test;

import java.util.concurrent.TimeUnit;

import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;

import java.util.concurrent.TimeUnit;

import org.neo4j.collection.primitive.Primitive;
import org.neo4j.collection.primitive.PrimitiveLongLongMap;
import org.neo4j.memory.GlobalMemoryTracker;
import org.neo4j.resources.CpuClock;

public class FakeCpuClock extends CpuClock implements TestRule
Expand All @@ -39,7 +40,7 @@ public long cpuTimeNanos( long threadId )
return -1;
}
};
private final PrimitiveLongLongMap cpuTimes = Primitive.offHeapLongLongMap();
private final PrimitiveLongLongMap cpuTimes = Primitive.offHeapLongLongMap( GlobalMemoryTracker.INSTANCE );

@Override
public long cpuTimeNanos( long threadId )
Expand Down
Expand Up @@ -24,14 +24,15 @@
import org.junit.runners.model.Statement;

import org.neo4j.collection.primitive.PrimitiveLongLongMap;
import org.neo4j.memory.GlobalMemoryTracker;
import org.neo4j.resources.HeapAllocation;

import static java.lang.Thread.currentThread;
import static org.neo4j.collection.primitive.Primitive.offHeapLongLongMap;

public class FakeHeapAllocation extends HeapAllocation implements TestRule
{
private final PrimitiveLongLongMap allocation = offHeapLongLongMap();
private final PrimitiveLongLongMap allocation = offHeapLongLongMap( GlobalMemoryTracker.INSTANCE );

@Override
public long allocatedBytes( long threadId )
Expand Down

0 comments on commit 5fb9e78

Please sign in to comment.