diff --git a/.gitignore b/.gitignore index 259148f..c5f07d8 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,9 @@ *.exe *.out *.app + +# Macos things +*.DS_Store +*.idea/ +*cmake-build* + diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..f118c8c --- /dev/null +++ b/.travis.yml @@ -0,0 +1,38 @@ +language: cpp +os: linux +dist: xenial +compiler: gcc + + +before_script: + - cd iz2 + - mkdir build + - cd build + +jobs: + # + # Valgrind + # + - os: linux + env: + - TEST="Valgrind" + addons: + apt: + packages: + - valgrind + script: + - cmake .. + - make + - ctest -T memcheck + + # + # CppCheck + # + - os: linux + env: + - TEST="CppCheck" + + script: + - cmake -DENABLE_CPPCHECK=ON .. + - make + - make check diff --git a/iz2/CMakeLists.txt b/iz2/CMakeLists.txt new file mode 100755 index 0000000..94c813d --- /dev/null +++ b/iz2/CMakeLists.txt @@ -0,0 +1,47 @@ +cmake_minimum_required(VERSION 3.1) + +project(iz1 C CXX) + +set(CMAKE_C_STANDARD 99) +set(CMAKE_CXX_STANDARD 17) +# +### GCOV +# + +if (ENABLE_GCOV) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftest-coverage -fprofile-arcs") +endif () + + +include(configure_test.cmake) +add_subdirectory(test) + +if (ENABLE_CPPCHECK) + include(configure_cppcheck.cmake) +endif () + +## +### Source definitions ### +## + +set(libmoodfinder_s_sources + ${PROJECT_SOURCE_DIR}/include/moodfinder.h + ${PROJECT_SOURCE_DIR}/include/moodfinder_errors.h + ${PROJECT_SOURCE_DIR}/src/moodfinder_s.c + ) + + +include_directories("${PROJECT_SOURCE_DIR}/include") + +add_library(libmoodfinder_s STATIC ${libmoodfinder_s_sources}) + +set(main_sources + ${PROJECT_SOURCE_DIR}/src/main.c + ${PROJECT_SOURCE_DIR}/src/moodfinder_profiler.c + ${PROJECT_SOURCE_DIR}/include/moodfinder_profile.h + ) + +add_executable(main ${main_sources}) +target_link_libraries(main libmoodfinder_s) + + diff --git a/iz2/README.MD b/iz2/README.MD new file mode 100755 index 0000000..48f66e4 --- /dev/null +++ b/iz2/README.MD @@ -0,0 +1,29 @@ +Вариант #23 +Сравните и выведите в консоль время работы последовательного и параллельного с использованием нескольких процессов +алгоритмов, каждый из которых выделяет в динамической памяти символьный массив размером 100 Мб и, +рассматривая его содержимое как абстрактную переписку, определяет эмоциональную окраску последней. Переписка считается +оптимистичной, если диграфов :) в ней больше, чем диграфов :(; в противном случае переписка признается пессимистичной. + +Результаты замеров +``` +100000 chars : 0.000568 seconds +600000 chars : 0.003453 seconds +1100000 chars : 0.005946 seconds +1600000 chars : 0.008527 seconds +2100000 chars : 0.011032 seconds +2600000 chars : 0.013986 seconds +3100000 chars : 0.016421 seconds +3600000 chars : 0.018687 seconds +4100000 chars : 0.021882 seconds +4600000 chars : 0.023492 seconds +5100000 chars : 0.026175 seconds +5600000 chars : 0.029254 seconds +6100000 chars : 0.031903 seconds +6600000 chars : 0.034180 seconds +7100000 chars : 0.036982 seconds +7600000 chars : 0.039288 seconds +8100000 chars : 0.042387 seconds +8600000 chars : 0.045159 seconds +9100000 chars : 0.048569 seconds +9600000 chars : 0.050803 seconds +``` diff --git a/iz2/configure_cppcheck.cmake b/iz2/configure_cppcheck.cmake new file mode 100644 index 0000000..66c9030 --- /dev/null +++ b/iz2/configure_cppcheck.cmake @@ -0,0 +1,39 @@ +## +### Cppcheck +## + +list(APPEND CPPCHECK_CMAKE_ARGS + "-DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}" + ) +include(ExternalProject) +ExternalProject_Add( + cppcheck + GIT_REPOSITORY https://github.com/danmar/cppcheck.git + GIT_TAG 1.79 + GIT_SHALLOW 1 + CMAKE_ARGS ${CPPCHECK_CMAKE_ARGS} + PREFIX ${CMAKE_BINARY_DIR}/external/cppcheck/prefix + TMP_DIR ${CMAKE_BINARY_DIR}/external/cppcheck/tmp + STAMP_DIR ${CMAKE_BINARY_DIR}/external/cppcheck/stamp + DOWNLOAD_DIR ${CMAKE_BINARY_DIR}/external/cppcheck/download + SOURCE_DIR ${CMAKE_BINARY_DIR}/external/cppcheck/src + BINARY_DIR ${CMAKE_BINARY_DIR}/external/cppcheck/build +) + +list(APPEND CPPCHECK_ARGS + --enable=warning,style,performance,portability,unusedFunction + --std=c99 + --verbose + --error-exitcode=1 + --language=c + -DMAIN=main + -I ${CMAKE_SOURCE_DIR}/include + ${CMAKE_SOURCE_DIR}/include/*.h + ${CMAKE_SOURCE_DIR}/src/*.c + ) + +add_custom_target( + check + COMMAND ${CMAKE_BINARY_DIR}/bin/cppcheck ${CPPCHECK_ARGS} + COMMENT "running cppcheck" +) diff --git a/iz2/configure_test.cmake b/iz2/configure_test.cmake new file mode 100644 index 0000000..6406a9e --- /dev/null +++ b/iz2/configure_test.cmake @@ -0,0 +1,26 @@ +## +### Valgrind +## + +set(MEMORYCHECK_COMMAND_OPTIONS "${MEMORYCHECK_COMMAND_OPTIONS} --leak-check=full") +set(MEMORYCHECK_COMMAND_OPTIONS "${MEMORYCHECK_COMMAND_OPTIONS} --track-fds=yes") +set(MEMORYCHECK_COMMAND_OPTIONS "${MEMORYCHECK_COMMAND_OPTIONS} --trace-children=yes") +set(MEMORYCHECK_COMMAND_OPTIONS "${MEMORYCHECK_COMMAND_OPTIONS} --error-exitcode=1") + +## +### Test definitions ### +## +include(CTest) + +configure_file(install_gtest.cmake + googletest-download/CMakeLists.txt) +execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download) +execute_process(COMMAND ${CMAKE_COMMAND} --build . + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download) + +add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src + ${CMAKE_BINARY_DIR}/googletest-build) + +enable_testing() + diff --git a/iz2/examples/clear_negative.txt b/iz2/examples/clear_negative.txt new file mode 100644 index 0000000..44a075c --- /dev/null +++ b/iz2/examples/clear_negative.txt @@ -0,0 +1 @@ +:(:(:(:(:(:(:(:(:(:(:(:(:(:(:(:(:(:(:(:( \ No newline at end of file diff --git a/iz2/examples/clear_positive.txt b/iz2/examples/clear_positive.txt new file mode 100644 index 0000000..0126061 --- /dev/null +++ b/iz2/examples/clear_positive.txt @@ -0,0 +1 @@ +:):):):):):):):):):):):):):):):):):):):) \ No newline at end of file diff --git a/iz2/examples/dirty_negative.txt b/iz2/examples/dirty_negative.txt new file mode 100644 index 0000000..fb1a4d6 --- /dev/null +++ b/iz2/examples/dirty_negative.txt @@ -0,0 +1 @@ +bpserqn:(grlbmyauwo:(flvvyw:(dt:(gtroemwi:(yflxrv:(vr:(nbaqwvbbxd:(:(fet:(zincficm:(rgozemxfw:(cwof:(rxrm:(zont:(gtufqcw:(:(ynydxbpox:(dmbjefj:(hwovhqxh:( \ No newline at end of file diff --git a/iz2/examples/dirty_positive.txt b/iz2/examples/dirty_positive.txt new file mode 100644 index 0000000..5acb75f --- /dev/null +++ b/iz2/examples/dirty_positive.txt @@ -0,0 +1 @@ +liaki:)bcnq:)uwh:)qnexbr:):)cxojtrerwb:)dj:)leag:)iw:)qlwstugh:)shjckmyao:)ssjhbxqd:)zcpihlvf:)ipfjwra:)f:)is:)tyx:):)tqfhe:)lkpixd:) \ No newline at end of file diff --git a/iz2/examples/empty.txt b/iz2/examples/empty.txt new file mode 100644 index 0000000..e69de29 diff --git a/iz2/examples/neutral.txt b/iz2/examples/neutral.txt new file mode 100644 index 0000000..140f766 --- /dev/null +++ b/iz2/examples/neutral.txt @@ -0,0 +1 @@ +:)hfc:(:)viexcm:(:):(:)veux:(:)xyomlgochx:(:)hkewbzhym:(:):(:)llu:(:):(:)wrrtzwhqgm:(:)qyxgxhesw:(:):(:)bdbhvwizxw:(:)ugfosxx:(:)oxs:(:)uwbfjeor:(:)kunsgh:(:)jpat:(:)f:(:)zqgotu:(:)skirkrregh:(:)mqo:(:)giuex:(:)uoz:(:)unedk:(:)ummgxloei:(:)pfvzxogd:(:)oottuozmew:(:)yadwlltyv:(:)ai:(:)zcvgdvou:(:)pw:(:)ww:(:)ptlrtm:(:)skdyh:(:)tovzyh:(:)ssgdchl:(:)tqqmkzd:(:)jdo:(:)qbfgusxuvk:(:):(:)pyo:(:)hnt:(:)dxkpznror:(:)iotfc:(:):(:)akyyyf:(:)oow:(:)guthbyfy:(:)yfxckx:(:)aqoorhxlvx:(:)jtikbnbnvd:(:)psffqnyiq:(:)vvcs:(:)eteraparaa:(:)jtxfwq:(:):(:)s:(:)ueciggoy:(:)wrwjmoda:(:):(:)sdsejmg:(:)yxotncs:(:)ddkjgb:(:)fn:(:)acjh:(:)toim:(:)swtu:(:)tglz:(:)mglvoj:(:)w:(:)htllhw:(:)sazwfryjew:(:)xbwaiz:(:)ofullgdip:(:)gkfgccf:(:)ejdptbb:(:)exqucqrrn:(:)sh:(:)sdcjuww:(:)nnffdp:(:):(:)qky:(:)qajnys:(:)qbntjbm:(:):(:)iutbwcaec:(:)zitjp:(:)bmsgjyfmo:(:)uizgq:(:)rasrxet:(:)ruy:(:):(:)gczhefir:(:)mwnhxkzxvj:(:)eb:(:)icw:(:)bdlnlbz:(:)wzyr:(:)kzvuwpu:( \ No newline at end of file diff --git a/iz2/examples/script.py b/iz2/examples/script.py new file mode 100644 index 0000000..4ff7994 --- /dev/null +++ b/iz2/examples/script.py @@ -0,0 +1,11 @@ +import string +import random + +file = open('neutral.txt', 'w') +letters = string.ascii_lowercase +count = 100 +for _ in range(count): + file.write(':)') + file.write(''.join([letters[random.randint(0, len(letters) - 1)] for i in range(random.randint(0, 10))])) + file.write(':(') +file.close() diff --git a/iz2/include/moodfinder.h b/iz2/include/moodfinder.h new file mode 100644 index 0000000..d310cfa --- /dev/null +++ b/iz2/include/moodfinder.h @@ -0,0 +1,5 @@ +#define POSITIVE 0 +#define NEGATIVE 1 +#define NEUTRAL 2 + +int find_mood(const char *filename); diff --git a/iz2/include/moodfinder_errors.h b/iz2/include/moodfinder_errors.h new file mode 100644 index 0000000..cedd780 --- /dev/null +++ b/iz2/include/moodfinder_errors.h @@ -0,0 +1,3 @@ +#define EMPTY_FILE_ERROR -2 +#define FILE_NOT_EXIST_ERROR -1 +#define MMAP_FAILED -3 \ No newline at end of file diff --git a/iz2/include/moodfinder_profile.h b/iz2/include/moodfinder_profile.h new file mode 100644 index 0000000..d5656fe --- /dev/null +++ b/iz2/include/moodfinder_profile.h @@ -0,0 +1,10 @@ +#ifndef IZ1_MOODFINDER_PROFILE_H +#define IZ1_MOODFINDER_PROFILE_H + +void generate_file(const char *filename, int status, int size); + +double profile_on_file(const char *filename, int count); + +void profile_app(int start_size, int end_size, int step); + +#endif //IZ1_MOODFINDER_PROFILE_H diff --git a/iz2/install_gtest.cmake b/iz2/install_gtest.cmake new file mode 100755 index 0000000..7499d73 --- /dev/null +++ b/iz2/install_gtest.cmake @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.1) + +project(extern-download NONE) + + +include(ExternalProject) +ExternalProject_Add( +googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG release-1.8.1 + SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src" + BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-build" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" +) diff --git a/iz2/src/main.c b/iz2/src/main.c new file mode 100644 index 0000000..9c2bd1c --- /dev/null +++ b/iz2/src/main.c @@ -0,0 +1,14 @@ +/* +Сравните и выведите в консоль время работы последовательного и параллельного с использованием +нескольких процессов алгоритмов, каждый из которых выделяет в динамической памяти символьный +массив размером 100 Мб и, рассматривая его содержимое как абстрактную переписку, определяет +эмоциональную окраску последней. Переписка считается оптимистичной, если диграфов :) в ней +больше, чем диграфов :(; в противном случае переписка признается пессимистичной. + */ +#include + +int main() +{ + profile_app(100000, 10000000, 500000); + return 0; +} diff --git a/iz2/src/moodfinder_profiler.c b/iz2/src/moodfinder_profiler.c new file mode 100644 index 0000000..754b4f9 --- /dev/null +++ b/iz2/src/moodfinder_profiler.c @@ -0,0 +1,53 @@ +#include "moodfinder_profile.h" + +#include "moodfinder.h" +#include "moodfinder_errors.h" + +#include +#include + +void generate_file(const char *filename, int status, int size) +{ + FILE *f = fopen(filename, "w"); + if (!f) + return; + char c = (char)(status == NEGATIVE ? '(' : ')'); + if (status == NEUTRAL) + { + size /= 2; + for (int i = 0; i < size; ++i) + fputs(":(", f); + } + for (int i = 0; i < size; ++i) + fprintf(f, ":%c", c); + fclose(f); +} + + +double profile_on_file(const char *filename, int count) +{ + struct timespec start, finish; + double mean_time = 0; + + for (int i = 0; i < count; ++i) + { + clock_gettime(CLOCK_MONOTONIC, &start); + find_mood(filename); + clock_gettime(CLOCK_MONOTONIC, &finish); + double elapsed = (double) (finish.tv_sec - start.tv_sec) + (double)(finish.tv_nsec - start.tv_nsec) / 1000000000.0; + mean_time += elapsed / (double)count; + } + return mean_time; +} + +void profile_app(int start_size, int end_size, int step) +{ + const char filename[] = "f.txt"; + for (int size = start_size; size <= end_size; size += step) + { + generate_file(filename, NEUTRAL, size); + double res = profile_on_file(filename, 10); + printf("%d chars : %lf seconds\n", size, res); + } +} + diff --git a/iz2/src/moodfinder_s.c b/iz2/src/moodfinder_s.c new file mode 100644 index 0000000..7f8cca8 --- /dev/null +++ b/iz2/src/moodfinder_s.c @@ -0,0 +1,40 @@ +#include "moodfinder.h" +#include "moodfinder_errors.h" + +#include +#include +#include +#include + + +int find_mood(const char *filename) +{ + int fd = open(filename, O_RDONLY); + if (fd == -1) + return FILE_NOT_EXIST_ERROR; + struct stat st; + stat(filename, &st); + size_t file_size = st.st_size; + char *region = mmap(NULL, + file_size, + PROT_READ, + (unsigned) MAP_SHARED | (unsigned) MAP_POPULATE, + fd, + 0); + if (region == MAP_FAILED) + { + close(fd); + if (file_size == 0) + return EMPTY_FILE_ERROR; + return MMAP_FAILED; + } + long long mood = 0; + for (size_t i = 0; i < file_size - 1; ++i) + { + if (region[i] == ':') + mood += (region[i + 1] == ')') + -1 * (region[i + 1] == '('); + } + munmap(region, file_size); + close(fd); + return mood > 0 ? POSITIVE : (mood == 0 ? NEUTRAL : NEGATIVE); +} \ No newline at end of file diff --git a/iz2/test/CMakeLists.txt b/iz2/test/CMakeLists.txt new file mode 100755 index 0000000..79092f5 --- /dev/null +++ b/iz2/test/CMakeLists.txt @@ -0,0 +1,26 @@ +include_directories("${PROJECT_SOURCE_DIR}/include") + +file(GLOB tests "${PROJECT_SOURCE_DIR}/test/*.cpp") +list(REMOVE_ITEM tests "${PROJECT_SOURCE_DIR}/test/main.cpp") + +if (ENABLE_GCOV) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftest-coverage -fprofile-arcs") +endif () + + +foreach (file ${tests}) + set(name) + get_filename_component(name ${file} NAME_WE) + add_executable("${name}_tests" + ${file} + "${PROJECT_SOURCE_DIR}/test/main.cpp" + ) + target_link_libraries("${name}_tests" + libmoodfinder_s + gtest_main + ) + add_test(NAME ${name} + COMMAND "${name}_tests" + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + ) +endforeach () \ No newline at end of file diff --git a/iz2/test/main.cpp b/iz2/test/main.cpp new file mode 100755 index 0000000..b42b721 --- /dev/null +++ b/iz2/test/main.cpp @@ -0,0 +1,6 @@ +#include "gtest/gtest.h" + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/iz2/test/moodfinder.cpp b/iz2/test/moodfinder.cpp new file mode 100644 index 0000000..8009016 --- /dev/null +++ b/iz2/test/moodfinder.cpp @@ -0,0 +1,59 @@ +#include "gtest/gtest.h" +#include + +using namespace std; + + +string construct_path(const string &filename) +{ + const static string examples = "examples/"; + return examples + filename; +} + +extern "C" { +#include "moodfinder.h" +#include "moodfinder_errors.h" +} + +TEST(find_mood_positive, clear) +{ + const string filename = "clear_positive.txt"; + ASSERT_EQ(find_mood(construct_path(filename).c_str()), POSITIVE); +} + +TEST(find_mood_positive, dirty) +{ + const string filename = "dirty_positive.txt"; + ASSERT_EQ(find_mood(construct_path(filename).c_str()), POSITIVE); +} + +TEST(find_mood_negative, clear) +{ + const string filename = "clear_negative.txt"; + ASSERT_EQ(find_mood(construct_path(filename).c_str()), NEGATIVE); +} + +TEST(find_mood_negative, dirty) +{ + const string filename = "dirty_negative.txt"; + ASSERT_EQ(find_mood(construct_path(filename).c_str()), NEGATIVE); +} + +TEST(find_mood_neutral, dirty) +{ + const string filename = "neutral.txt"; + ASSERT_EQ(find_mood(construct_path(filename).c_str()), NEUTRAL); +} + +TEST(find_mood_errors, empty) +{ + const string filename = "empty.txt"; + ASSERT_EQ(find_mood(construct_path(filename).c_str()), EMPTY_FILE_ERROR); +} + +TEST(find_mood_errors, not_exitsing) +{ + const string s = construct_path("not_existing.txt"); + static const char *filename = s.c_str(); + ASSERT_EQ(find_mood(filename), FILE_NOT_EXIST_ERROR); +}