Several benchmarks for C interop (#2659)

This commit is contained in:
LepilkinaElena
2019-02-19 10:04:25 +03:00
committed by GitHub
parent e8d6a2a5f1
commit 904350d42e
19 changed files with 766 additions and 4 deletions
+2 -2
View File
@@ -19,10 +19,10 @@ buildscript {
task konanRun {
subprojects.each {
dependsOn it.getTasksByName('konanRun', true)[0]
dependsOn it.getTasksByName('konanRun', true)[0]
}
}
task jvmRun {
subprojects.each {
dependsOn it.getTasksByName('jvmRun', true)[0]
+13
View File
@@ -0,0 +1,13 @@
project.ext {
applicationName = 'Cinterop'
commonSrcDirs = ['../../tools/benchmarks/shared/src', 'src/main/kotlin', '../shared/src/main/kotlin', '../../tools/kliopt']
jvmSrcDirs = ['src/main/kotlin-jvm', '../shared/src/main/kotlin-jvm']
nativeSrcDirs = ['src/main/kotlin-native', '../shared/src/main/kotlin-native']
}
apply from: rootProject.file('gradle/benchmark.gradle')
kotlin.targets.native.compilations.main.cinterops {
macros
struct
types
}
+1
View File
@@ -0,0 +1 @@
org.jetbrains.kotlin.native.home=../../dist
@@ -0,0 +1,27 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.structsBenchmarks
actual fun structBenchmark() {
error("Benchmark structBenchmark is unsupported on JVM!")
}
actual fun unionBenchmark() {
error("Benchmark unionBenchmark is unsupported on JVM!")
}
actual fun enumBenchmark() {
error("Benchmark enumBenchmark is unsupported on JVM!")
}
@@ -0,0 +1,21 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.structsProducedByMacrosBenchmarks
actual fun macrosBenchmark() {
error("Benchmark macrosBenchmark is unsupported on JVM!")
}
@@ -0,0 +1,46 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.typesBenchmarks
actual class StringBenchmark actual constructor() {
actual fun stringToCBenchmark() {
error("Benchmark stringToCBenchmark is unsupported on JVM!")
}
actual fun stringToKotlinBenchmark() {
error("Benchmark stringToKotlinBenchmark is unsupported on JVM!")
}
}
actual class IntBenchmark actual constructor() {
actual fun intBenchmark() {
error("Benchmark intBenchmark is unsupported on JVM!")
}
}
actual class BoxedIntBenchmark actual constructor() {
actual fun boxedIntBenchmark() {
error("Benchmark boxedIntBenchmark is unsupported on JVM!")
}
}
actual class IntMatrixBenchmark actual constructor() {
actual fun intMatrixBenchmark() {
error("Benchmark intMatrixBenchmark is unsupported on JVM!")
}
}
@@ -0,0 +1,80 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.structsBenchmarks
import kotlinx.cinterop.*
import kotlin.math.sqrt
const val benchmarkSize = 10000
actual fun structBenchmark() {
memScoped {
val containsFunction = staticCFunction<CPointer<ElementS>?, CPointer<ElementS>?, Int> { first, second ->
if (first == null || second == null) {
0
} else if (first.pointed.string.toKString().contains(second.pointed.string.toKString())) {
1
}
else {
0
}
}
val elementsList = mutableListOf<ElementS>()
// Fill list.
for (i in 1..benchmarkSize) {
val element = alloc<ElementS>()
element.floatValue = i + sqrt(i.toDouble()).toFloat()
element.integer = i.toLong()
itoa(i, element.string, 10)
element.contains = containsFunction
elementsList.add(element)
}
val summary = elementsList.map { multiplyElementS(it.readValue(), (0..10).random()) }
.reduce { acc, it -> sumElementSPtr(acc.ptr, it.ptr)!!.pointed.readValue() }
val intValue = summary.useContents { integer }
elementsList.last().contains!!(elementsList.last().ptr, elementsList.first().ptr)
}
}
actual fun unionBenchmark() {
memScoped {
val elementsList = mutableListOf<ElementU>()
// Fill list.
for (i in 1..benchmarkSize) {
val element = alloc<ElementU>()
element.integer = i.toLong()
elementsList.add(element)
}
elementsList.forEach {
it.floatValue = it.integer + sqrt(it.integer.toDouble()).toFloat()
}
val summary = elementsList.map { multiplyElementU(it.readValue(), (0..10).random()) }
.reduce { acc, it -> sumElementUPtr(acc.ptr, it.ptr)!!.pointed.readValue() }
summary.useContents { integer }
}
}
actual fun enumBenchmark() {
val days = arrayOf("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday")
val enumValues = mutableListOf<WeekDay>()
for (i in 1..benchmarkSize) {
enumValues.add(getWeekDay(days[(0..6).random()]))
}
enumValues.forEach {
isWeekEnd(it)
}
}
@@ -0,0 +1,59 @@
/*
* Copyright 2010-2019 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.structsProducedByMacrosBenchmarks
import kotlinx.cinterop.*
import kotlin.math.abs
const val benachmarkSize = 1000
actual fun macrosBenchmark() {
memScoped {
val ints = new_list_int()
for (i in 1..benachmarkSize) {
list_push_front_int(ints, i)
}
val floats = new_list_float()
// Copy integer list to float one.
ints?.pointed?.apply {
var current = _first
while(current != null) {
list_push_front_float(floats, current?.pointed?._data?.toFloat()
?: error("Null elements in list are not expected!")
)
current = current?.pointed?._next
}
}
// Reverse list.
var previous: CPointer<list_elem_float>? = null
var current = floats?.pointed?._first
while (current != null) {
val next = current?.pointed?._next
current?.pointed?._next = previous
previous = current
current = next
}
floats?.pointed?._first = previous
free_list_int(ints)
try {
if (abs(list_front_float(floats) - benachmarkSize.toFloat()) > 0.00001) {
error("Wrong first element!")
}
} finally {
free_list_float(floats)
}
}
}
@@ -0,0 +1,132 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.typesBenchmarks
import kotlin.random.Random
import kotlinx.cinterop.*
const val benchmarkSize = 1000
actual class StringBenchmark actual constructor() {
val charPool: List<Char> = ('a'..'z') + ('A'..'Z') + ('0'..'9')
val randomString = generateRandomString()
val randomChar = charPool[Random.nextInt(0, charPool.size)]
val strings = mutableListOf<String>()
init {
// Generate random strings.
for (i in 1..benchmarkSize) {
strings.add(generateRandomString())
}
}
fun generateRandomString(): String {
return (1..benchmarkSize)
.map { i -> Random.nextInt(0, charPool.size) }
.map(charPool::get)
.joinToString("")
}
actual fun stringToCBenchmark() {
// Generate random strings.
for (i in 1..benchmarkSize) {
charFrequency(randomString, randomChar.toByte())
}
}
actual fun stringToKotlinBenchmark() {
memScoped {
val result = StringBuilder()
for (i in 1..benchmarkSize) {
val pointer = findSuitableString(strings.toCStringArray(this), benchmarkSize, "a")
result.append(pointer?.toKString())
nativeHeap.free(pointer.rawValue)
}
}
}
}
actual class IntMatrixBenchmark actual constructor(){
val matrixSize = 1000
val first = generateMatrix(matrixSize)
val second = generateMatrix(matrixSize)
fun generateMatrix(size: Int): Array<IntArray> {
val matrix = Array(size, { IntArray(size) })
for (i in (0 until size)) {
for (j in (0 until size)) {
matrix[i][j] = (1..20).random()
}
}
return matrix
}
actual fun intMatrixBenchmark() {
memScoped {
val result = allocArray<CPointerVar<IntVar>>(matrixSize)
for (i in (0 until matrixSize)) {
result[i] = allocArray<IntVar>(matrixSize)
}
val resultMatrix = multiplyMatrix(matrixSize, matrixSize,
first.map { it.toCValues().ptr }.toCValues().ptr,
matrixSize, matrixSize,
second.map { it.toCValues().ptr }.toCValues().ptr)
val resultOutput = buildString {
for (i in (0 until matrixSize)) {
for (j in (0 until matrixSize)) {
append(resultMatrix!![i]!![j])
append(" ")
}
append("\n")
}
}
}
}
}
actual class IntBenchmark actual constructor() {
val size = 20
val array = Array<Int>(size, { (0 until size).random() })
actual fun intBenchmark() {
for (i in 1..benchmarkSize) {
average(array[0], array[1], array[2], array[3], array[4], array[5], array[6], array[7], array[8],
array[9], array[10], array[11], array[12], array[13], array[14], array[15], array[16],
array[17], array[18], array[19])
}
}
}
actual class BoxedIntBenchmark actual constructor() {
val size = 20
val array = Array<Int?>(size, { null })
init {
for (i in (0 until size)) {
val element: Int? = (0 until size).random()
array[i] = element
}
}
actual fun boxedIntBenchmark() {
for (i in 1..benchmarkSize) {
average(array[0]!!, array[1]!!, array[2]!!, array[3]!!, array[4]!!, array[5]!!, array[6]!!, array[7]!!, array[8]!!,
array[9]!!, array[10]!!, array[11]!!, array[12]!!, array[13]!!, array[14]!!, array[15]!!, array[16]!!,
array[17]!!, array[18]!!, array[19]!!)
}
}
}
@@ -0,0 +1,48 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import org.jetbrains.structsProducedByMacrosBenchmarks.*
import org.jetbrains.benchmarksLauncher.*
import org.jetbrains.structsBenchmarks.*
import org.jetbrains.typesBenchmarks.*
import org.jetbrains.kliopt.*
class CinteropLauncher(numWarmIterations: Int, numberOfAttempts: Int, prefix: String): Launcher(numWarmIterations, numberOfAttempts, prefix) {
val stringBenchmark = StringBenchmark()
val intMatrixBenchmark = IntMatrixBenchmark()
val intBenchmark = IntBenchmark()
val boxedIntBenchmark = BoxedIntBenchmark()
override val benchmarks = BenchmarksCollection(
mutableMapOf(
"macros" to ::macrosBenchmark,
"struct" to ::structBenchmark,
"union" to ::unionBenchmark,
"enum" to ::enumBenchmark,
"stringToC" to stringBenchmark::stringToCBenchmark,
"stringToKotlin" to stringBenchmark::stringToKotlinBenchmark,
"intMatrix" to intMatrixBenchmark::intMatrixBenchmark,
"int" to intBenchmark::intBenchmark,
"boxedInt" to boxedIntBenchmark::boxedIntBenchmark
)
)
}
fun main(args: Array<String>) {
BenchmarksRunner.runBenchmarks(args, { parser: ArgParser ->
CinteropLauncher(parser.get<Int>("warmup")!!, parser.get<Int>("repeat")!!, parser.get<String>("prefix")!!).launch(parser.getAll<String>("filter"))
})
}
@@ -0,0 +1,21 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.structsBenchmarks
expect fun structBenchmark()
expect fun unionBenchmark()
expect fun enumBenchmark()
@@ -0,0 +1,19 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.structsProducedByMacrosBenchmarks
expect fun macrosBenchmark()
@@ -0,0 +1,31 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.typesBenchmarks
expect class StringBenchmark() {
fun stringToCBenchmark()
fun stringToKotlinBenchmark()
}
expect class IntBenchmark() {
fun intBenchmark()
}
expect class BoxedIntBenchmark() {
fun boxedIntBenchmark()
}
expect class IntMatrixBenchmark() {
fun intMatrixBenchmark()
}
@@ -0,0 +1,93 @@
package = org.jetbrains.structsProducedByMacrosBenchmarks
---
#include <stdio.h>
#include <stdlib.h>
#define define_list(type) \
\
struct _list_##type; \
\
typedef struct \
{ \
int (*is_empty)(const struct _list_##type*); \
size_t (*size)(const struct _list_##type*); \
const type (*front)(const struct _list_##type*); \
void (*push_front)(struct _list_##type*, type); \
} _list_functions_##type; \
\
typedef struct _list_elem_##type \
{ \
type _data; \
struct _list_elem_##type* _next; \
} list_elem_##type; \
\
typedef struct _list_##type \
{ \
size_t _size; \
list_elem_##type* _first; \
list_elem_##type* _last; \
_list_functions_##type* _functions; \
} List_##type; \
\
List_##type* new_list_##type(); \
int list_is_empty_##type(const List_##type* list); \
size_t list_size_##type(const List_##type* list); \
const type list_front_##type(const List_##type* list); \
void list_push_front_##type(List_##type* list, type elem); \
\
int list_is_empty_##type(const List_##type* list) \
{ \
return list->_size == 0; \
} \
\
size_t list_size_##type(const List_##type* list) \
{ \
return list->_size; \
} \
\
const type list_front_##type(const List_##type* list) \
{ \
return list->_first->_data; \
} \
\
void list_push_front_##type(List_##type* list, type elem) \
{ \
struct _list_elem_##type* element = (struct _list_elem_##type*) malloc(sizeof(struct _list_elem_##type)); \
element->_data = elem; \
element->_next = list->_first; \
list->_first = element; \
list->_size++; \
} \
\
_list_functions_##type _list_funcs_##type = { \
&list_is_empty_##type, \
&list_size_##type, \
&list_front_##type, \
&list_push_front_##type, \
}; \
\
List_##type* new_list_##type() \
{ \
List_##type* res = (List_##type*) malloc(sizeof(List_##type)); \
res->_size = 0; \
res->_first = NULL; \
res->_functions = &_list_funcs_##type; \
return res; \
} \
\
void free_list_##type(List_##type* list) \
{ \
struct _list_elem_##type* current = list->_first; \
while (current != NULL) \
{ \
struct _list_elem_##type* next = current->_next; \
free(current); \
current = next; \
} \
free(list); \
}
define_list(int)
define_list(float)
@@ -0,0 +1,105 @@
package = org.jetbrains.structsBenchmarks
strictEnums = WeekDay
---
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
enum WeekDay {Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday};
int isWeekEnd(enum WeekDay day) {
if (day == Saturday || day == Sunday)
return 1;
return 0;
}
enum WeekDay getWeekDay(const char* date) {
if (strstr(date, "Sunday") != NULL) {
return Sunday;
} else if (strstr(date, "Monday") != NULL) {
return Monday;
} else if (strstr(date, "Tuesday") != NULL) {
return Tuesday;
} else if (strstr(date, "Wednesday") != NULL) {
return Wednesday;
} else if (strstr(date, "Thursday") != NULL) {
return Thursday;
} else if (strstr(date, "Friday") != NULL) {
return Friday;
} else if (strstr(date, "Saturday") != NULL) {
return Saturday;
}
abort();
}
struct ElementS {
long long integer;
float floatValue;
char string[32];
int (*contains)(const struct ElementS*, const struct ElementS*);
};
int elementContains(const struct ElementS* self, const struct ElementS* other) {
if (self == NULL || other == NULL) {
return 0;
}
if (strstr(self->string, other->string) != NULL) {
return 1;
}
return 0;
}
union ElementU {
long long integer;
float floatValue;
char string[32];
};
union ElementU multiplyElementU(union ElementU element, int coefficient) {
union ElementU newElement;
newElement.integer = coefficient * element.integer;
return newElement;
}
struct ElementS multiplyElementS(struct ElementS element, int coefficient) {
struct ElementS newElement;
newElement.integer = coefficient * element.integer;
newElement.floatValue = coefficient * element.floatValue;
int i = 0;
while (element.string[i] != '\0') {
newElement.string[i] = coefficient * element.string[i];
i++;
}
return newElement;
}
void itoa(int val, char* buffer, int base){
int i = 30;
for(; val && i ; --i, val /= base)
buffer[i] = "0123456789abcdef"[val % base];
buffer[31] = '\0';
}
union ElementU* sumElementUPtr(const union ElementU* first, const union ElementU* second) {
if (first == NULL || second == NULL) {
return NULL;
}
union ElementU* newElement = (union ElementU*)malloc(sizeof(union ElementU));
newElement->integer = first->integer + second->integer;
return newElement;
}
struct ElementS* sumElementSPtr(const struct ElementS* first, const struct ElementS* second) {
if (first == NULL || second == NULL) {
return NULL;
}
struct ElementS* newElement = (struct ElementS*)malloc(sizeof(struct ElementS));
newElement->integer = first->integer + second->integer;
newElement->floatValue = first->floatValue + second->floatValue;
itoa(newElement->integer, newElement->string, 10);
return newElement;
}
@@ -0,0 +1,64 @@
package = org.jetbrains.typesBenchmarks
---
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
int charFrequency(const char* string, char charToFind) {
int frequency = 0;
for(int i = 0; string[i] != '\0'; ++i) {
if(charToFind == string[i])
++frequency;
}
return frequency;
}
const char* findSuitableString(const char* stringsArray[], int arraySize, const char* stringToFind) {
for(int i = 0; i < arraySize; ++i) {
if (strstr(stringsArray[i], stringToFind) != NULL) {
char* result = (char*) malloc((strlen(stringsArray[i])+1)*sizeof(char));
strcpy(result, stringsArray[i]);
return result;
}
}
return NULL;
}
unsigned long int sum(int array[], int arraySize) {
unsigned long int result = 0;
for(int i = 0; i < arraySize; ++i) {
result += array[i];
}
return result;
}
double average(int count, ...) {
va_list list;
int j = 0;
va_start(list, count);
double sum = 0;
for(j=0; j<count; j++) {
sum += va_arg(list, int);
}
va_end(list);
return sum / count;
}
int** multiplyMatrix(int m1, int m2, const int** mat1, int n1, int n2, const int** mat2) {
int x, i, j;
int **res = (int **)malloc(m1 * sizeof(int *));
for (i=0; i<m1; i++) {
res[i] = (int *)malloc(n2 * sizeof(int));
}
for (i = 0; i < m1; i++) {
for (j = 0; j < n2; j++) {
res[i][j] = 0;
for (x = 0; x < m2; x++) {
res[i][j] += mat1[i][x] * mat2[x][j];
}
}
}
return res;
}
+1
View File
@@ -3,5 +3,6 @@ project.ext {
commonSrcDirs = ['../../tools/benchmarks/shared/src', 'src/main/kotlin', '../shared/src/main/kotlin', '../../tools/kliopt']
jvmSrcDirs = ['src/main/kotlin-jvm', '../shared/src/main/kotlin-jvm']
nativeSrcDirs = ['src/main/kotlin-native', '../shared/src/main/kotlin-native']
}
apply from: rootProject.file('gradle/benchmark.gradle')
+2 -1
View File
@@ -1 +1,2 @@
include ':ring'
include ':ring'
include ':cinterop'
@@ -21,7 +21,7 @@ import kotlinx.cinterop.*
import libcurl.*
actual fun readFile(fileName: String): String {
val file = fopen(fileName, "r") ?: error("Cannot write file '$fileName'")
val file = fopen(fileName, "r") ?: error("Cannot read file '$fileName'")
var buffer = ByteArray(1024)
var text = StringBuilder()
try {