Core Principles Profiling First : Always profile before optimizing Data Structures : Choose appropriate data structures for the task Vectorization : Leverage R's vectorized operations Memory Management : Optimize memory usage and garbage collection Parallel Processing : Utilize multiple cores when beneficial Profiling and Benchmarking Code Profiling # R/01-profiling.R
#' Comprehensive code profiling
#'
#' @param code_expression Code expression to profile
#' @param profiling_type Type of profiling
#' @return Profiling results
profile_code <- function ( code_expression , profiling_type = "line" ) {
if ( profiling_type == "line" ) {
return ( profile_line_by_line ( code_expression ))
} else if ( profiling_type == "function" ) {
return ( profile_function_calls ( code_expression ))
} else if ( profiling_type == "memory" ) {
return ( profile_memory_usage ( code_expression ))
}
}
#' Profile code line by line
#'
#' @param code_expression Code expression
#' @return Line-by-line profiling results
profile_line_by_line <- function ( code_expression ) {
library ( profvis )
# Create temporary file for code
temp_file <- tempfile ( fileext = ".R" )
writeLines ( deparse ( substitute ( code_expression )), temp_file )
# Profile the code
prof_results <- profvis ({
eval ( code_expression )
})
# Clean up
unlink ( temp_file )
return ( prof_results )
}
#' Profile function calls
#'
#' @param code_expression Code expression
#' @return Function call profiling results
profile_function_calls <- function ( code_expression ) {
library ( profr )
# Profile function calls
prof_results <- profr ({
eval ( code_expression )
})
return ( prof_results )
}
#' Profile memory usage
#'
#' @param code_expression Code expression
#' @return Memory profiling results
profile_memory_usage <- function ( code_expression ) {
library ( pryr )
# Get memory before
memory_before <- mem_used ()
# Execute code
result <- eval ( code_expression )
# Get memory after
memory_after <- mem_used ()
# Calculate memory usage
memory_usage <- memory_after - memory_before
return ( list (
memory_before = memory_before ,
memory_after = memory_after ,
memory_usage = memory_usage ,
result = result
))
}
#' Benchmark multiple implementations
#'
#' @param implementations List of implementations to benchmark
#' @param data Data to test with
#' @param iterations Number of iterations
#' @return Benchmark results
benchmark_implementations <- function ( implementations , data , iterations = 100 ) {
library ( microbenchmark )
# Create benchmark expressions
benchmark_exprs <- lapply ( implementations , function ( impl ) {
substitute ( impl ( data ))
})
# Run benchmark
benchmark_results <- microbenchmark (
list = benchmark_exprs ,
times = iterations ,
unit = "ms"
)
return ( benchmark_results )
}
#' Analyze benchmark results
#'
#' @param benchmark_results Benchmark results
#' @return Analysis of benchmark results
analyze_benchmark_results <- function ( benchmark_results ) {
# Calculate summary statistics
summary_stats <- summary ( benchmark_results )
# Find fastest implementation
fastest_idx <- which.min ( summary_stats $ median )
fastest_implementation <- levels ( benchmark_results $ expr )[ fastest_idx ]
# Calculate relative performance
relative_performance <- summary_stats $ median / min ( summary_stats $ median )
return ( list (
summary = summary_stats ,
fastest = fastest_implementation ,
relative_performance = relative_performance
))
}
# R/01-profiling.R (continued)
#' Monitor system performance
#'
#' @param duration Monitoring duration in seconds
#' @param interval Monitoring interval in seconds
#' @return System performance data
monitor_system_performance <- function ( duration = 60 , interval = 1 ) {
performance_data <- data.frame (
timestamp = numeric ( 0 ),
cpu_usage = numeric ( 0 ),
memory_usage = numeric ( 0 ),
gc_count = numeric ( 0 )
)
start_time <- Sys.time ()
while ( as.numeric ( Sys.time () - start_time ) < duration ) {
# Get current performance metrics
current_time <- Sys.time ()
cpu_usage <- get_cpu_usage ()
memory_usage <- get_memory_usage ()
gc_count <- get_gc_count ()
# Add to performance data
performance_data <- rbind ( performance_data , data.frame (
timestamp = as.numeric ( current_time ),
cpu_usage = cpu_usage ,
memory_usage = memory_usage ,
gc_count = gc_count
))
# Wait for next interval
Sys.sleep ( interval )
}
return ( performance_data )
}
#' Get CPU usage
#'
#' @return CPU usage percentage
get_cpu_usage <- function () {
# This is a simplified version - in practice, you'd use system-specific methods
system_info <- system ( "top -l 1 | grep 'CPU usage'" , intern = TRUE )
if ( length ( system_info ) > 0 ) {
cpu_match <- regmatches ( system_info , regexpr ( "[0-9.]+%" , system_info ))
if ( length ( cpu_match ) > 0 ) {
return ( as.numeric ( gsub ( "%" , "" , cpu_match [ 1 ])))
}
}
return ( 0 )
}
#' Get memory usage
#'
#' @return Memory usage in MB
get_memory_usage <- function () {
memory_info <- gc ()
return ( sum ( memory_info [, 2 ]))
}
#' Get garbage collection count
#'
#' @return Garbage collection count
get_gc_count <- function () {
gc_info <- gc ()
return ( sum ( gc_info [, 1 ]))
}
Data Structure Optimization Efficient Data Structures # R/02-data-structures.R
#' Optimize data structures for performance
#'
#' @param data Data to optimize
#' @param optimization_type Type of optimization
#' @return Optimized data
optimize_data_structures <- function ( data , optimization_type ) {
switch ( optimization_type ,
"data_table" = convert_to_data_table ( data ),
"matrix" = convert_to_matrix ( data ),
"sparse" = convert_to_sparse ( data ),
"factor" = optimize_factors ( data ),
stop ( "Unsupported optimization type: " , optimization_type )
)
}
#' Convert to data.table
#'
#' @param data Data frame
#' @return data.table object
convert_to_data_table <- function ( data ) {
library ( data.table )
# Convert to data.table
dt <- as.data.table ( data )
# Set key for faster lookups
if ( ncol ( dt ) > 0 ) {
setkey ( dt , names ( dt )[ 1 ])
}
return ( dt )
}
#' Convert to matrix
#'
#' @param data Data frame
#' @return Matrix object
convert_to_matrix <- function ( data ) {
# Convert to matrix
matrix_data <- as.matrix ( data )
# Set row and column names
rownames ( matrix_data ) <- rownames ( data )
colnames ( matrix_data ) <- colnames ( data )
return ( matrix_data )
}
#' Convert to sparse matrix
#'
#' @param data Data frame
#' @return Sparse matrix object
convert_to_sparse <- function ( data ) {
library ( Matrix )
# Convert to sparse matrix
sparse_data <- as ( data , "sparseMatrix" )
return ( sparse_data )
}
#' Optimize factors
#'
#' @param data Data frame
#' @return Data with optimized factors
optimize_factors <- function ( data ) {
optimized_data <- data
# Convert character columns to factors
for ( col in names ( data )) {
if ( is.character ( data [[ col ]])) {
optimized_data [[ col ]] <- as.factor ( data [[ col ]])
}
}
# Remove unused factor levels
for ( col in names ( optimized_data )) {
if ( is.factor ( optimized_data [[ col ]])) {
optimized_data [[ col ]] <- droplevels ( optimized_data [[ col ]])
}
}
return ( optimized_data )
}
Memory Optimization # R/02-data-structures.R (continued)
#' Optimize memory usage
#'
#' @param data Data to optimize
#' @param optimization_type Type of memory optimization
#' @return Memory-optimized data
optimize_memory_usage <- function ( data , optimization_type ) {
switch ( optimization_type ,
"remove_duplicates" = remove_duplicates ( data ),
"compress_data" = compress_data ( data ),
"lazy_loading" = enable_lazy_loading ( data ),
"chunk_processing" = enable_chunk_processing ( data ),
stop ( "Unsupported optimization type: " , optimization_type )
)
}
#' Remove duplicate rows
#'
#' @param data Data frame
#' @return Data without duplicates
remove_duplicates <- function ( data ) {
# Remove duplicate rows
unique_data <- unique ( data )
return ( unique_data )
}
#' Compress data
#'
#' @param data Data frame
#' @return Compressed data
compress_data <- function ( data ) {
# Use more memory-efficient data types
compressed_data <- data
for ( col in names ( data )) {
if ( is.numeric ( data [[ col ]])) {
# Use integer if possible
if ( all ( data [[ col ]] == as.integer ( data [[ col ]]), na.rm = TRUE )) {
compressed_data [[ col ]] <- as.integer ( data [[ col ]])
} else {
# Use single precision if possible
if ( all ( abs ( data [[ col ]]) < 3.4e38 , na.rm = TRUE )) {
compressed_data [[ col ]] <- as.single ( data [[ col ]])
}
}
} else if ( is.character ( data [[ col ]])) {
# Convert to factor if many repeated values
if ( length ( unique ( data [[ col ]])) < length ( data [[ col ]]) * 0.5 ) {
compressed_data [[ col ]] <- as.factor ( data [[ col ]])
}
}
}
return ( compressed_data )
}
#' Enable lazy loading
#'
#' @param data Data frame
#' @return Lazy-loaded data
enable_lazy_loading <- function ( data ) {
library ( dplyr )
# Convert to lazy data frame
lazy_data <- lazy_df ( data )
return ( lazy_data )
}
#' Enable chunk processing
#'
#' @param data Data frame
#' @param chunk_size Chunk size
#' @return Chunked data
enable_chunk_processing <- function ( data , chunk_size = 1000 ) {
# Create chunk indices
n_rows <- nrow ( data )
chunk_indices <- split ( 1 : n_rows , ceiling ( seq_along ( 1 : n_rows ) / chunk_size ))
# Create chunked data structure
chunked_data <- list (
data = data ,
chunk_indices = chunk_indices ,
chunk_size = chunk_size
)
return ( chunked_data )
}
Vectorization and Optimization Vectorized Operations # R/03-vectorization.R
#' Optimize code using vectorization
#'
#' @param code_expression Code expression to optimize
#' @param optimization_type Type of vectorization
#' @return Optimized code
optimize_with_vectorization <- function ( code_expression , optimization_type ) {
switch ( optimization_type ,
"apply_family" = optimize_with_apply_family ( code_expression ),
"vectorized_math" = optimize_with_vectorized_math ( code_expression ),
"matrix_operations" = optimize_with_matrix_operations ( code_expression ),
"string_operations" = optimize_with_string_operations ( code_expression ),
stop ( "Unsupported optimization type: " , optimization_type )
)
}
#' Optimize using apply family
#'
#' @param code_expression Code expression
#' @return Optimized code
optimize_with_apply_family <- function ( code_expression ) {
# Replace loops with apply functions
optimized_code <- substitute ({
# Use lapply instead of for loops
result <- lapply ( data , function ( x ) {
# Vectorized operation
x * 2
})
})
return ( optimized_code )
}
#' Optimize using vectorized math
#'
#' @param code_expression Code expression
#' @return Optimized code
optimize_with_vectorized_math <- function ( code_expression ) {
# Replace element-wise operations with vectorized operations
optimized_code <- substitute ({
# Vectorized mathematical operations
result <- sqrt ( x ^ 2 + y ^ 2 )
})
return ( optimized_code )
}
#' Optimize using matrix operations
#'
#' @param code_expression Code expression
#' @return Optimized code
optimize_with_matrix_operations <- function ( code_expression ) {
# Use matrix operations instead of loops
optimized_code <- substitute ({
# Matrix multiplication
result <- matrix1 %*% matrix2
})
return ( optimized_code )
}
#' Optimize using string operations
#'
#' @param code_expression Code expression
#' @return Optimized code
optimize_with_string_operations <- function ( code_expression ) {
# Use vectorized string operations
optimized_code <- substitute ({
# Vectorized string operations
result <- toupper ( strings )
})
return ( optimized_code )
}
Loop Optimization # R/03-vectorization.R (continued)
#' Optimize loops for performance
#'
#' @param loop_code Loop code to optimize
#' @param optimization_type Type of loop optimization
#' @return Optimized loop code
optimize_loops <- function ( loop_code , optimization_type ) {
switch ( optimization_type ,
"preallocate" = preallocate_vectors ( loop_code ),
"vectorize" = vectorize_loop ( loop_code ),
"parallelize" = parallelize_loop ( loop_code ),
"unroll" = unroll_loop ( loop_code ),
stop ( "Unsupported optimization type: " , optimization_type )
)
}
#' Preallocate vectors in loops
#'
#' @param loop_code Loop code
#' @return Optimized loop code
preallocate_vectors <- function ( loop_code ) {
# Preallocate result vectors
optimized_code <- substitute ({
# Preallocate result vector
result <- numeric ( length ( input ))
# Loop with preallocated vector
for ( i in seq_along ( input )) {
result [ i ] <- input [ i ] * 2
}
})
return ( optimized_code )
}
#' Vectorize loop
#'
#' @param loop_code Loop code
#' @return Vectorized code
vectorize_loop <- function ( loop_code ) {
# Replace loop with vectorized operation
optimized_code <- substitute ({
# Vectorized operation
result <- input * 2
})
return ( optimized_code )
}
#' Parallelize loop
#'
#' @param loop_code Loop code
#' @return Parallelized code
parallelize_loop <- function ( loop_code ) {
# Use parallel processing
optimized_code <- substitute ({
library ( parallel )
# Set up parallel processing
cores <- detectCores ()
cl <- makeCluster ( cores )
# Parallel loop
result <- parLapply ( cl , input , function ( x ) {
x * 2
})
# Clean up
stopCluster ( cl )
})
return ( optimized_code )
}
#' Unroll loop
#'
#' @param loop_code Loop code
#' @return Unrolled loop code
unroll_loop <- function ( loop_code ) {
# Unroll small loops
optimized_code <- substitute ({
# Unrolled loop
result [ 1 ] <- input [ 1 ] * 2
result [ 2 ] <- input [ 2 ] * 2
result [ 3 ] <- input [ 3 ] * 2
result [ 4 ] <- input [ 4 ] * 2
})
return ( optimized_code )
}
Parallel Processing Multi-core Processing # R/04-parallel-processing.R
#' Optimize code using parallel processing
#'
#' @param code_expression Code expression to parallelize
#' @param parallel_type Type of parallel processing
#' @param parameters Parallel processing parameters
#' @return Parallelized code
optimize_with_parallel_processing <- function ( code_expression , parallel_type , parameters = list ()) {
switch ( parallel_type ,
"foreach" = parallelize_with_foreach ( code_expression , parameters ),
"parallel" = parallelize_with_parallel ( code_expression , parameters ),
"future" = parallelize_with_future ( code_expression , parameters ),
"mclapply" = parallelize_with_mclapply ( code_expression , parameters ),
stop ( "Unsupported parallel type: " , parallel_type )
)
}
#' Parallelize using foreach
#'
#' @param code_expression Code expression
#' @param parameters Parallel parameters
#' @return Parallelized code
parallelize_with_foreach <- function ( code_expression , parameters ) {
library ( foreach )
library ( doParallel )
# Set up parallel backend
cores <- parameters $ cores %||% detectCores ()
cl <- makeCluster ( cores )
registerDoParallel ( cl )
# Parallelized code
parallelized_code <- substitute ({
result <- foreach ( i = 1 : n , .combine = c ) %dopar% {
# Parallel computation
compute_function ( data [ i ])
}
})
# Clean up
stopCluster ( cl )
return ( parallelized_code )
}
#' Parallelize using parallel package
#'
#' @param code_expression Code expression
#' @param parameters Parallel parameters
#' @return Parallelized code
parallelize_with_parallel <- function ( code_expression , parameters ) {
library ( parallel )
# Set up parallel processing
cores <- parameters $ cores %||% detectCores ()
cl <- makeCluster ( cores )
# Parallelized code
parallelized_code <- substitute ({
result <- parLapply ( cl , data , function ( x ) {
# Parallel computation
compute_function ( x )
})
})
# Clean up
stopCluster ( cl )
return ( parallelized_code )
}
#' Parallelize using future
#'
#' @param code_expression Code expression
#' @param parameters Parallel parameters
#' @return Parallelized code
parallelize_with_future <- function ( code_expression , parameters ) {
library ( future )
library ( future.apply )
# Set up parallel processing
plan ( multisession , workers = parameters $ cores %||% detectCores ())
# Parallelized code
parallelized_code <- substitute ({
result <- future_lapply ( data , function ( x ) {
# Parallel computation
compute_function ( x )
})
})
return ( parallelized_code )
}
#' Parallelize using mclapply
#'
#' @param code_expression Code expression
#' @param parameters Parallel parameters
#' @return Parallelized code
parallelize_with_mclapply <- function ( code_expression , parameters ) {
library ( parallel )
# Parallelized code
parallelized_code <- substitute ({
result <- mclapply ( data , function ( x ) {
# Parallel computation
compute_function ( x )
}, mc.cores = parameters $ cores %||% detectCores ())
})
return ( parallelized_code )
}
Distributed Computing # R/04-parallel-processing.R (continued)
#' Optimize code using distributed computing
#'
#' @param code_expression Code expression to distribute
#' @param distributed_type Type of distributed computing
#' @param parameters Distributed computing parameters
#' @return Distributed code
optimize_with_distributed_computing <- function ( code_expression , distributed_type , parameters = list ()) {
switch ( distributed_type ,
"spark" = distribute_with_spark ( code_expression , parameters ),
"hadoop" = distribute_with_hadoop ( code_expression , parameters ),
"mpi" = distribute_with_mpi ( code_expression , parameters ),
stop ( "Unsupported distributed type: " , distributed_type )
)
}
#' Distribute using Spark
#'
#' @param code_expression Code expression
#' @param parameters Spark parameters
#' @return Distributed code
distribute_with_spark <- function ( code_expression , parameters ) {
library ( sparklyr )
# Connect to Spark
sc <- spark_connect ( master = parameters $ master %||% "local" )
# Distributed code
distributed_code <- substitute ({
# Copy data to Spark
spark_data <- copy_to ( sc , data , "spark_data" )
# Perform distributed computation
result <- spark_data %>%
spark_apply ( function ( x ) {
# Distributed computation
compute_function ( x )
})
})
# Clean up
spark_disconnect ( sc )
return ( distributed_code )
}
#' Distribute using Hadoop
#'
#' @param code_expression Code expression
#' @param parameters Hadoop parameters
#' @return Distributed code
distribute_with_hadoop <- function ( code_expression , parameters ) {
library ( rhdfs )
library ( rmr2 )
# Set up Hadoop
hdfs.init ()
# Distributed code
distributed_code <- substitute ({
# Map function
map_function <- function ( k , v ) {
# Map computation
keyval ( k , compute_function ( v ))
}
# Reduce function
reduce_function <- function ( k , v ) {
# Reduce computation
keyval ( k , sum ( v ))
}
# Run MapReduce job
result <- mapreduce (
input = parameters $ input_path ,
output = parameters $ output_path ,
map = map_function ,
reduce = reduce_function
)
})
return ( distributed_code )
}
Memory Management Garbage Collection Optimization # R/05-memory-management.R
#' Optimize garbage collection
#'
#' @param code_expression Code expression to optimize
#' @param gc_type Type of garbage collection
#' @return Optimized code
optimize_garbage_collection <- function ( code_expression , gc_type = "auto" ) {
switch ( gc_type ,
"auto" = optimize_auto_gc ( code_expression ),
"manual" = optimize_manual_gc ( code_expression ),
"tuning" = optimize_gc_tuning ( code_expression ),
stop ( "Unsupported GC type: " , gc_type )
)
}
#' Optimize automatic garbage collection
#'
#' @param code_expression Code expression
#' @return Optimized code
optimize_auto_gc <- function ( code_expression ) {
# Let R handle garbage collection automatically
optimized_code <- substitute ({
# Code with automatic GC
result <- compute_function ( data )
})
return ( optimized_code )
}
#' Optimize manual garbage collection
#'
#' @param code_expression Code expression
#' @return Optimized code
optimize_manual_gc <- function ( code_expression ) {
# Manually control garbage collection
optimized_code <- substitute ({
# Disable automatic GC
gc ( verbose = FALSE )
# Code execution
result <- compute_function ( data )
# Force garbage collection
gc ( verbose = FALSE )
})
return ( optimized_code )
}
#' Optimize GC tuning
#'
#' @param code_expression Code expression
#' @return Optimized code
optimize_gc_tuning <- function ( code_expression ) {
# Tune garbage collection parameters
optimized_code <- substitute ({
# Set GC tuning parameters
gc ( verbose = FALSE , reset = TRUE )
# Code execution
result <- compute_function ( data )
# Tune GC parameters
gc ( verbose = FALSE , reset = FALSE )
})
return ( optimized_code )
}
Memory Profiling # R/05-memory-management.R (continued)
#' Profile memory usage
#'
#' @param code_expression Code expression to profile
#' @return Memory profiling results
profile_memory_usage <- function ( code_expression ) {
library ( pryr )
# Get memory before
memory_before <- mem_used ()
# Execute code
result <- eval ( code_expression )
# Get memory after
memory_after <- mem_used ()
# Calculate memory usage
memory_usage <- memory_after - memory_before
# Get object sizes
object_sizes <- sapply ( ls (), function ( x ) object_size ( get ( x )))
return ( list (
memory_before = memory_before ,
memory_after = memory_after ,
memory_usage = memory_usage ,
object_sizes = object_sizes ,
result = result
))
}
#' Optimize memory usage
#'
#' @param code_expression Code expression to optimize
#' @param optimization_type Type of memory optimization
#' @return Optimized code
optimize_memory_usage <- function ( code_expression , optimization_type ) {
switch ( optimization_type ,
"remove_objects" = remove_unused_objects ( code_expression ),
"compress_objects" = compress_objects ( code_expression ),
"lazy_evaluation" = enable_lazy_evaluation ( code_expression ),
stop ( "Unsupported optimization type: " , optimization_type )
)
}
#' Remove unused objects
#'
#' @param code_expression Code expression
#' @return Optimized code
remove_unused_objects <- function ( code_expression ) {
# Remove unused objects
optimized_code <- substitute ({
# Code execution
result <- compute_function ( data )
# Remove unused objects
rm ( unused_object1 , unused_object2 )
# Force garbage collection
gc ( verbose = FALSE )
})
return ( optimized_code )
}
#' Compress objects
#'
#' @param code_expression Code expression
#' @return Optimized code
compress_objects <- function ( code_expression ) {
# Compress objects to save memory
optimized_code <- substitute ({
# Compress data
compressed_data <- compress ( data )
# Code execution
result <- compute_function ( compressed_data )
# Decompress result
decompressed_result <- decompress ( result )
})
return ( optimized_code )
}
#' Enable lazy evaluation
#'
#' @param code_expression Code expression
#' @return Optimized code
enable_lazy_evaluation <- function ( code_expression ) {
# Use lazy evaluation to save memory
optimized_code <- substitute ({
# Create lazy data structure
lazy_data <- lazy_df ( data )
# Code execution with lazy evaluation
result <- compute_function ( lazy_data )
})
return ( optimized_code )
}
TL;DR Runbook Quick Start # 1. Profile code
prof_results <- profile_code ( compute_function ( data ), "line" )
# 2. Benchmark implementations
bench_results <- benchmark_implementations ( list ( impl1 , impl2 ), data )
# 3. Optimize data structures
optimized_data <- optimize_data_structures ( data , "data_table" )
# 4. Vectorize operations
vectorized_code <- optimize_with_vectorization ( loop_code , "apply_family" )
# 5. Parallelize processing
parallel_code <- optimize_with_parallel_processing ( code , "foreach" , list ( cores = 4 ))
# 6. Optimize memory usage
memory_optimized <- optimize_memory_usage ( code , "remove_objects" )
Essential Patterns # Complete performance optimization pipeline
optimize_performance <- function ( code , data , optimization_config ) {
# Profile current performance
prof_results <- profile_code ( code )
# Benchmark different implementations
bench_results <- benchmark_implementations ( optimization_config $ implementations , data )
# Optimize data structures
optimized_data <- optimize_data_structures ( data , optimization_config $ data_structure )
# Vectorize operations
vectorized_code <- optimize_with_vectorization ( code , optimization_config $ vectorization )
# Parallelize if beneficial
if ( optimization_config $ parallelize ) {
parallel_code <- optimize_with_parallel_processing ( vectorized_code ,
optimization_config $ parallel_type ,
optimization_config $ parallel_params )
}
# Optimize memory usage
memory_optimized <- optimize_memory_usage ( parallel_code , optimization_config $ memory_optimization )
return ( memory_optimized )
}